github.com/ewagmig/fabric@v2.1.1+incompatible/core/ledger/kvledger/txmgmt/statedb/commontests/test_common.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package commontests
     8  
     9  import (
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/statedb"
    14  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version"
    15  	"github.com/stretchr/testify/assert"
    16  )
    17  
    18  // TestGetStateMultipleKeys tests read for given multiple keys
    19  func TestGetStateMultipleKeys(t *testing.T, dbProvider statedb.VersionedDBProvider) {
    20  	db, err := dbProvider.GetDBHandle("testgetmultiplekeys")
    21  	assert.NoError(t, err)
    22  
    23  	// Test that savepoint is nil for a new state db
    24  	sp, err := db.GetLatestSavePoint()
    25  	assert.NoError(t, err, "Error upon GetLatestSavePoint()")
    26  	assert.Nil(t, sp)
    27  
    28  	batch := statedb.NewUpdateBatch()
    29  	expectedValues := make([]*statedb.VersionedValue, 2)
    30  	vv1 := statedb.VersionedValue{Value: []byte("value1"), Version: version.NewHeight(1, 1)}
    31  	expectedValues[0] = &vv1
    32  	vv2 := statedb.VersionedValue{Value: []byte("value2"), Version: version.NewHeight(1, 2)}
    33  	expectedValues[1] = &vv2
    34  	vv3 := statedb.VersionedValue{Value: []byte("value3"), Version: version.NewHeight(1, 3)}
    35  	vv4 := statedb.VersionedValue{Value: []byte{}, Version: version.NewHeight(1, 4)}
    36  	batch.Put("ns1", "key1", vv1.Value, vv1.Version)
    37  	batch.Put("ns1", "key2", vv2.Value, vv2.Version)
    38  	batch.Put("ns2", "key3", vv3.Value, vv3.Version)
    39  	batch.Put("ns2", "key4", vv4.Value, vv4.Version)
    40  	savePoint := version.NewHeight(2, 5)
    41  	db.ApplyUpdates(batch, savePoint)
    42  
    43  	actualValues, _ := db.GetStateMultipleKeys("ns1", []string{"key1", "key2"})
    44  	assert.Equal(t, expectedValues, actualValues)
    45  }
    46  
    47  // TestBasicRW tests basic read-write
    48  func TestBasicRW(t *testing.T, dbProvider statedb.VersionedDBProvider) {
    49  	db, err := dbProvider.GetDBHandle("testbasicrw")
    50  	assert.NoError(t, err)
    51  
    52  	// Test that savepoint is nil for a new state db
    53  	sp, err := db.GetLatestSavePoint()
    54  	assert.NoError(t, err, "Error upon GetLatestSavePoint()")
    55  	assert.Nil(t, sp)
    56  
    57  	// Test retrieval of non-existent key - returns nil rather than error
    58  	// For more details see https://github.com/hyperledger-archives/fabric/issues/936.
    59  	val, err := db.GetState("ns", "key1")
    60  	assert.NoError(t, err, "Should receive nil rather than error upon reading non existent key")
    61  	assert.Nil(t, val)
    62  
    63  	batch := statedb.NewUpdateBatch()
    64  	vv1 := statedb.VersionedValue{Value: []byte("value1"), Version: version.NewHeight(1, 1)}
    65  	vv2 := statedb.VersionedValue{Value: []byte("value2"), Version: version.NewHeight(1, 2)}
    66  	vv3 := statedb.VersionedValue{Value: []byte("value3"), Version: version.NewHeight(1, 3)}
    67  	vv4 := statedb.VersionedValue{Value: []byte{}, Version: version.NewHeight(1, 4)}
    68  	vv5 := statedb.VersionedValue{Value: []byte("null"), Version: version.NewHeight(1, 5)}
    69  	batch.Put("ns1", "key1", vv1.Value, vv1.Version)
    70  	batch.Put("ns1", "key2", vv2.Value, vv2.Version)
    71  	batch.Put("ns2", "key3", vv3.Value, vv3.Version)
    72  	batch.Put("ns2", "key4", vv4.Value, vv4.Version)
    73  	batch.Put("ns2", "key5", vv5.Value, vv5.Version)
    74  	savePoint := version.NewHeight(2, 5)
    75  	db.ApplyUpdates(batch, savePoint)
    76  
    77  	vv, _ := db.GetState("ns1", "key1")
    78  	assert.Equal(t, &vv1, vv)
    79  
    80  	vv, _ = db.GetState("ns2", "key4")
    81  	assert.Equal(t, &vv4, vv)
    82  
    83  	vv, _ = db.GetState("ns2", "key5")
    84  	assert.Equal(t, &vv5, vv)
    85  
    86  	sp, err = db.GetLatestSavePoint()
    87  	assert.NoError(t, err)
    88  	assert.Equal(t, savePoint, sp)
    89  
    90  }
    91  
    92  // TestMultiDBBasicRW tests basic read-write on multiple dbs
    93  func TestMultiDBBasicRW(t *testing.T, dbProvider statedb.VersionedDBProvider) {
    94  	db1, err := dbProvider.GetDBHandle("testmultidbbasicrw")
    95  	assert.NoError(t, err)
    96  
    97  	db2, err := dbProvider.GetDBHandle("testmultidbbasicrw2")
    98  	assert.NoError(t, err)
    99  
   100  	batch1 := statedb.NewUpdateBatch()
   101  	vv1 := statedb.VersionedValue{Value: []byte("value1_db1"), Version: version.NewHeight(1, 1)}
   102  	vv2 := statedb.VersionedValue{Value: []byte("value2_db1"), Version: version.NewHeight(1, 2)}
   103  	batch1.Put("ns1", "key1", vv1.Value, vv1.Version)
   104  	batch1.Put("ns1", "key2", vv2.Value, vv2.Version)
   105  	savePoint1 := version.NewHeight(1, 2)
   106  	db1.ApplyUpdates(batch1, savePoint1)
   107  
   108  	batch2 := statedb.NewUpdateBatch()
   109  	vv3 := statedb.VersionedValue{Value: []byte("value1_db2"), Version: version.NewHeight(1, 4)}
   110  	vv4 := statedb.VersionedValue{Value: []byte("value2_db2"), Version: version.NewHeight(1, 5)}
   111  	batch2.Put("ns1", "key1", vv3.Value, vv3.Version)
   112  	batch2.Put("ns1", "key2", vv4.Value, vv4.Version)
   113  	savePoint2 := version.NewHeight(1, 5)
   114  	db2.ApplyUpdates(batch2, savePoint2)
   115  
   116  	vv, _ := db1.GetState("ns1", "key1")
   117  	assert.Equal(t, &vv1, vv)
   118  
   119  	sp, err := db1.GetLatestSavePoint()
   120  	assert.NoError(t, err)
   121  	assert.Equal(t, savePoint1, sp)
   122  
   123  	vv, _ = db2.GetState("ns1", "key1")
   124  	assert.Equal(t, &vv3, vv)
   125  
   126  	sp, err = db2.GetLatestSavePoint()
   127  	assert.NoError(t, err)
   128  	assert.Equal(t, savePoint2, sp)
   129  }
   130  
   131  // TestDeletes tests deletes
   132  func TestDeletes(t *testing.T, dbProvider statedb.VersionedDBProvider) {
   133  	db, err := dbProvider.GetDBHandle("testdeletes")
   134  	assert.NoError(t, err)
   135  
   136  	batch := statedb.NewUpdateBatch()
   137  	vv1 := statedb.VersionedValue{Value: []byte("value1"), Version: version.NewHeight(1, 1)}
   138  	vv2 := statedb.VersionedValue{Value: []byte("value2"), Version: version.NewHeight(1, 2)}
   139  	vv3 := statedb.VersionedValue{Value: []byte("value1"), Version: version.NewHeight(1, 3)}
   140  	vv4 := statedb.VersionedValue{Value: []byte("value2"), Version: version.NewHeight(1, 4)}
   141  
   142  	batch.Put("ns", "key1", vv1.Value, vv1.Version)
   143  	batch.Put("ns", "key2", vv2.Value, vv2.Version)
   144  	batch.Put("ns", "key3", vv2.Value, vv3.Version)
   145  	batch.Put("ns", "key4", vv2.Value, vv4.Version)
   146  	batch.Delete("ns", "key3", version.NewHeight(1, 5))
   147  	savePoint := version.NewHeight(1, 5)
   148  	err = db.ApplyUpdates(batch, savePoint)
   149  	assert.NoError(t, err)
   150  	vv, _ := db.GetState("ns", "key2")
   151  	assert.Equal(t, &vv2, vv)
   152  
   153  	vv, err = db.GetState("ns", "key3")
   154  	assert.NoError(t, err)
   155  	assert.Nil(t, vv)
   156  
   157  	batch = statedb.NewUpdateBatch()
   158  	batch.Delete("ns", "key2", version.NewHeight(1, 6))
   159  	err = db.ApplyUpdates(batch, savePoint)
   160  	assert.NoError(t, err)
   161  	vv, err = db.GetState("ns", "key2")
   162  	assert.NoError(t, err)
   163  	assert.Nil(t, vv)
   164  }
   165  
   166  // TestIterator tests the iterator
   167  func TestIterator(t *testing.T, dbProvider statedb.VersionedDBProvider) {
   168  	db, err := dbProvider.GetDBHandle("testiterator")
   169  	assert.NoError(t, err)
   170  	db.Open()
   171  	defer db.Close()
   172  	batch := statedb.NewUpdateBatch()
   173  	batch.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 1))
   174  	batch.Put("ns1", "key2", []byte("value2"), version.NewHeight(1, 2))
   175  	batch.Put("ns1", "key3", []byte("value3"), version.NewHeight(1, 3))
   176  	batch.Put("ns1", "key4", []byte("value4"), version.NewHeight(1, 4))
   177  	batch.Put("ns2", "key5", []byte("value5"), version.NewHeight(1, 5))
   178  	batch.Put("ns2", "key6", []byte("value6"), version.NewHeight(1, 6))
   179  	batch.Put("ns3", "key7", []byte("value7"), version.NewHeight(1, 7))
   180  	savePoint := version.NewHeight(2, 5)
   181  	db.ApplyUpdates(batch, savePoint)
   182  	itr1, _ := db.GetStateRangeScanIterator("ns1", "key1", "")
   183  	testItr(t, itr1, []string{"key1", "key2", "key3", "key4"})
   184  
   185  	itr2, _ := db.GetStateRangeScanIterator("ns1", "key2", "key3")
   186  	testItr(t, itr2, []string{"key2"})
   187  
   188  	itr3, _ := db.GetStateRangeScanIterator("ns1", "", "")
   189  	testItr(t, itr3, []string{"key1", "key2", "key3", "key4"})
   190  
   191  	itr4, _ := db.GetStateRangeScanIterator("ns2", "", "")
   192  	testItr(t, itr4, []string{"key5", "key6"})
   193  
   194  }
   195  
   196  func testItr(t *testing.T, itr statedb.ResultsIterator, expectedKeys []string) {
   197  	defer itr.Close()
   198  	for _, expectedKey := range expectedKeys {
   199  		queryResult, _ := itr.Next()
   200  		vkv := queryResult.(*statedb.VersionedKV)
   201  		key := vkv.Key
   202  		assert.Equal(t, expectedKey, key)
   203  	}
   204  	_, err := itr.Next()
   205  	assert.NoError(t, err)
   206  }
   207  
   208  // TestQuery tests queries
   209  func TestQuery(t *testing.T, dbProvider statedb.VersionedDBProvider) {
   210  	db, err := dbProvider.GetDBHandle("testquery")
   211  	assert.NoError(t, err)
   212  	db.Open()
   213  	defer db.Close()
   214  	batch := statedb.NewUpdateBatch()
   215  	jsonValue1 := `{"asset_name": "marble1","color": "blue","size": 1,"owner": "tom"}`
   216  	batch.Put("ns1", "key1", []byte(jsonValue1), version.NewHeight(1, 1))
   217  	jsonValue2 := `{"asset_name": "marble2","color": "blue","size": 2,"owner": "jerry"}`
   218  	batch.Put("ns1", "key2", []byte(jsonValue2), version.NewHeight(1, 2))
   219  	jsonValue3 := `{"asset_name": "marble3","color": "blue","size": 3,"owner": "fred"}`
   220  	batch.Put("ns1", "key3", []byte(jsonValue3), version.NewHeight(1, 3))
   221  	jsonValue4 := `{"asset_name": "marble4","color": "blue","size": 4,"owner": "martha"}`
   222  	batch.Put("ns1", "key4", []byte(jsonValue4), version.NewHeight(1, 4))
   223  	jsonValue5 := `{"asset_name": "marble5","color": "blue","size": 5,"owner": "fred"}`
   224  	batch.Put("ns1", "key5", []byte(jsonValue5), version.NewHeight(1, 5))
   225  	jsonValue6 := `{"asset_name": "marble6","color": "blue","size": 6,"owner": "elaine"}`
   226  	batch.Put("ns1", "key6", []byte(jsonValue6), version.NewHeight(1, 6))
   227  	jsonValue7 := `{"asset_name": "marble7","color": "blue","size": 7,"owner": "fred"}`
   228  	batch.Put("ns1", "key7", []byte(jsonValue7), version.NewHeight(1, 7))
   229  	jsonValue8 := `{"asset_name": "marble8","color": "blue","size": 8,"owner": "elaine"}`
   230  	batch.Put("ns1", "key8", []byte(jsonValue8), version.NewHeight(1, 8))
   231  	jsonValue9 := `{"asset_name": "marble9","color": "green","size": 9,"owner": "fred"}`
   232  	batch.Put("ns1", "key9", []byte(jsonValue9), version.NewHeight(1, 9))
   233  	jsonValue10 := `{"asset_name": "marble10","color": "green","size": 10,"owner": "mary"}`
   234  	batch.Put("ns1", "key10", []byte(jsonValue10), version.NewHeight(1, 10))
   235  	jsonValue11 := `{"asset_name": "marble11","color": "cyan","size": 1000007,"owner": "joe"}`
   236  	batch.Put("ns1", "key11", []byte(jsonValue11), version.NewHeight(1, 11))
   237  
   238  	//add keys for a separate namespace
   239  	batch.Put("ns2", "key1", []byte(jsonValue1), version.NewHeight(1, 12))
   240  	batch.Put("ns2", "key2", []byte(jsonValue2), version.NewHeight(1, 13))
   241  	batch.Put("ns2", "key3", []byte(jsonValue3), version.NewHeight(1, 14))
   242  	batch.Put("ns2", "key4", []byte(jsonValue4), version.NewHeight(1, 15))
   243  	batch.Put("ns2", "key5", []byte(jsonValue5), version.NewHeight(1, 16))
   244  	batch.Put("ns2", "key6", []byte(jsonValue6), version.NewHeight(1, 17))
   245  	batch.Put("ns2", "key7", []byte(jsonValue7), version.NewHeight(1, 18))
   246  	batch.Put("ns2", "key8", []byte(jsonValue8), version.NewHeight(1, 19))
   247  	batch.Put("ns2", "key9", []byte(jsonValue9), version.NewHeight(1, 20))
   248  	batch.Put("ns2", "key10", []byte(jsonValue10), version.NewHeight(1, 21))
   249  
   250  	savePoint := version.NewHeight(2, 22)
   251  	db.ApplyUpdates(batch, savePoint)
   252  
   253  	// query for owner=jerry, use namespace "ns1"
   254  	itr, err := db.ExecuteQuery("ns1", `{"selector":{"owner":"jerry"}}`)
   255  	assert.NoError(t, err)
   256  
   257  	// verify one jerry result
   258  	queryResult1, err := itr.Next()
   259  	assert.NoError(t, err)
   260  	assert.NotNil(t, queryResult1)
   261  	versionedQueryRecord := queryResult1.(*statedb.VersionedKV)
   262  	stringRecord := string(versionedQueryRecord.Value)
   263  	bFoundRecord := strings.Contains(stringRecord, "jerry")
   264  	assert.True(t, bFoundRecord)
   265  
   266  	// verify no more results
   267  	queryResult2, err := itr.Next()
   268  	assert.NoError(t, err)
   269  	assert.Nil(t, queryResult2)
   270  
   271  	// query for owner=jerry, use namespace "ns2"
   272  	itr, err = db.ExecuteQuery("ns2", `{"selector":{"owner":"jerry"}}`)
   273  	assert.NoError(t, err)
   274  
   275  	// verify one jerry result
   276  	queryResult1, err = itr.Next()
   277  	assert.NoError(t, err)
   278  	assert.NotNil(t, queryResult1)
   279  	versionedQueryRecord = queryResult1.(*statedb.VersionedKV)
   280  	stringRecord = string(versionedQueryRecord.Value)
   281  	bFoundRecord = strings.Contains(stringRecord, "jerry")
   282  	assert.True(t, bFoundRecord)
   283  
   284  	// verify no more results
   285  	queryResult2, err = itr.Next()
   286  	assert.NoError(t, err)
   287  	assert.Nil(t, queryResult2)
   288  
   289  	// query for owner=jerry, use namespace "ns3"
   290  	itr, err = db.ExecuteQuery("ns3", `{"selector":{"owner":"jerry"}}`)
   291  	assert.NoError(t, err)
   292  
   293  	// verify results - should be no records
   294  	queryResult1, err = itr.Next()
   295  	assert.NoError(t, err)
   296  	assert.Nil(t, queryResult1)
   297  
   298  	// query using bad query string
   299  	itr, err = db.ExecuteQuery("ns1", "this is an invalid query string")
   300  	assert.Error(t, err, "Should have received an error for invalid query string")
   301  
   302  	// query returns 0 records
   303  	itr, err = db.ExecuteQuery("ns1", `{"selector":{"owner":"not_a_valid_name"}}`)
   304  	assert.NoError(t, err)
   305  
   306  	// verify no results
   307  	queryResult3, err := itr.Next()
   308  	assert.NoError(t, err)
   309  	assert.Nil(t, queryResult3)
   310  
   311  	// query with fields, namespace "ns1"
   312  	itr, err = db.ExecuteQuery("ns1", `{"selector":{"owner":"jerry"},"fields": ["owner", "asset_name", "color", "size"]}`)
   313  	assert.NoError(t, err)
   314  
   315  	// verify one jerry result
   316  	queryResult1, err = itr.Next()
   317  	assert.NoError(t, err)
   318  	assert.NotNil(t, queryResult1)
   319  	versionedQueryRecord = queryResult1.(*statedb.VersionedKV)
   320  	stringRecord = string(versionedQueryRecord.Value)
   321  	bFoundRecord = strings.Contains(stringRecord, "jerry")
   322  	assert.True(t, bFoundRecord)
   323  
   324  	// verify no more results
   325  	queryResult2, err = itr.Next()
   326  	assert.NoError(t, err)
   327  	assert.Nil(t, queryResult2)
   328  
   329  	// query with fields, namespace "ns2"
   330  	itr, err = db.ExecuteQuery("ns2", `{"selector":{"owner":"jerry"},"fields": ["owner", "asset_name", "color", "size"]}`)
   331  	assert.NoError(t, err)
   332  
   333  	// verify one jerry result
   334  	queryResult1, err = itr.Next()
   335  	assert.NoError(t, err)
   336  	assert.NotNil(t, queryResult1)
   337  	versionedQueryRecord = queryResult1.(*statedb.VersionedKV)
   338  	stringRecord = string(versionedQueryRecord.Value)
   339  	bFoundRecord = strings.Contains(stringRecord, "jerry")
   340  	assert.True(t, bFoundRecord)
   341  
   342  	// verify no more results
   343  	queryResult2, err = itr.Next()
   344  	assert.NoError(t, err)
   345  	assert.Nil(t, queryResult2)
   346  
   347  	// query with fields, namespace "ns3"
   348  	itr, err = db.ExecuteQuery("ns3", `{"selector":{"owner":"jerry"},"fields": ["owner", "asset_name", "color", "size"]}`)
   349  	assert.NoError(t, err)
   350  
   351  	// verify no results
   352  	queryResult1, err = itr.Next()
   353  	assert.NoError(t, err)
   354  	assert.Nil(t, queryResult1)
   355  
   356  	// query with complex selector, namespace "ns1"
   357  	itr, err = db.ExecuteQuery("ns1", `{"selector":{"$and":[{"size":{"$gt": 5}},{"size":{"$lt":8}},{"$not":{"size":6}}]}}`)
   358  	assert.NoError(t, err)
   359  
   360  	// verify one fred result
   361  	queryResult1, err = itr.Next()
   362  	assert.NoError(t, err)
   363  	assert.NotNil(t, queryResult1)
   364  	versionedQueryRecord = queryResult1.(*statedb.VersionedKV)
   365  	stringRecord = string(versionedQueryRecord.Value)
   366  	bFoundRecord = strings.Contains(stringRecord, "fred")
   367  	assert.True(t, bFoundRecord)
   368  
   369  	// verify no more results
   370  	queryResult2, err = itr.Next()
   371  	assert.NoError(t, err)
   372  	assert.Nil(t, queryResult2)
   373  
   374  	// query with complex selector, namespace "ns2"
   375  	itr, err = db.ExecuteQuery("ns2", `{"selector":{"$and":[{"size":{"$gt": 5}},{"size":{"$lt":8}},{"$not":{"size":6}}]}}`)
   376  	assert.NoError(t, err)
   377  
   378  	// verify one fred result
   379  	queryResult1, err = itr.Next()
   380  	assert.NoError(t, err)
   381  	assert.NotNil(t, queryResult1)
   382  	versionedQueryRecord = queryResult1.(*statedb.VersionedKV)
   383  	stringRecord = string(versionedQueryRecord.Value)
   384  	bFoundRecord = strings.Contains(stringRecord, "fred")
   385  	assert.True(t, bFoundRecord)
   386  
   387  	// verify no more results
   388  	queryResult2, err = itr.Next()
   389  	assert.NoError(t, err)
   390  	assert.Nil(t, queryResult2)
   391  
   392  	// query with complex selector, namespace "ns3"
   393  	itr, err = db.ExecuteQuery("ns3", `{"selector":{"$and":[{"size":{"$gt": 5}},{"size":{"$lt":8}},{"$not":{"size":6}}]}}`)
   394  	assert.NoError(t, err)
   395  
   396  	// verify no more results
   397  	queryResult1, err = itr.Next()
   398  	assert.NoError(t, err)
   399  	assert.Nil(t, queryResult1)
   400  
   401  	// query with embedded implicit "AND" and explicit "OR", namespace "ns1"
   402  	itr, err = db.ExecuteQuery("ns1", `{"selector":{"color":"green","$or":[{"owner":"fred"},{"owner":"mary"}]}}`)
   403  	assert.NoError(t, err)
   404  
   405  	// verify one green result
   406  	queryResult1, err = itr.Next()
   407  	assert.NoError(t, err)
   408  	assert.NotNil(t, queryResult1)
   409  	versionedQueryRecord = queryResult1.(*statedb.VersionedKV)
   410  	stringRecord = string(versionedQueryRecord.Value)
   411  	bFoundRecord = strings.Contains(stringRecord, "green")
   412  	assert.True(t, bFoundRecord)
   413  
   414  	// verify another green result
   415  	queryResult2, err = itr.Next()
   416  	assert.NoError(t, err)
   417  	assert.NotNil(t, queryResult2)
   418  	versionedQueryRecord = queryResult2.(*statedb.VersionedKV)
   419  	stringRecord = string(versionedQueryRecord.Value)
   420  	bFoundRecord = strings.Contains(stringRecord, "green")
   421  	assert.True(t, bFoundRecord)
   422  
   423  	// verify no more results
   424  	queryResult3, err = itr.Next()
   425  	assert.NoError(t, err)
   426  	assert.Nil(t, queryResult3)
   427  
   428  	// query with embedded implicit "AND" and explicit "OR", namespace "ns2"
   429  	itr, err = db.ExecuteQuery("ns2", `{"selector":{"color":"green","$or":[{"owner":"fred"},{"owner":"mary"}]}}`)
   430  	assert.NoError(t, err)
   431  
   432  	// verify one green result
   433  	queryResult1, err = itr.Next()
   434  	assert.NoError(t, err)
   435  	assert.NotNil(t, queryResult1)
   436  	versionedQueryRecord = queryResult1.(*statedb.VersionedKV)
   437  	stringRecord = string(versionedQueryRecord.Value)
   438  	bFoundRecord = strings.Contains(stringRecord, "green")
   439  	assert.True(t, bFoundRecord)
   440  
   441  	// verify another green result
   442  	queryResult2, err = itr.Next()
   443  	assert.NoError(t, err)
   444  	assert.NotNil(t, queryResult2)
   445  	versionedQueryRecord = queryResult2.(*statedb.VersionedKV)
   446  	stringRecord = string(versionedQueryRecord.Value)
   447  	bFoundRecord = strings.Contains(stringRecord, "green")
   448  	assert.True(t, bFoundRecord)
   449  
   450  	// verify no more results
   451  	queryResult3, err = itr.Next()
   452  	assert.NoError(t, err)
   453  	assert.Nil(t, queryResult3)
   454  
   455  	// query with embedded implicit "AND" and explicit "OR", namespace "ns3"
   456  	itr, err = db.ExecuteQuery("ns3", `{"selector":{"color":"green","$or":[{"owner":"fred"},{"owner":"mary"}]}}`)
   457  	assert.NoError(t, err)
   458  
   459  	// verify no results
   460  	queryResult1, err = itr.Next()
   461  	assert.NoError(t, err)
   462  	assert.Nil(t, queryResult1)
   463  
   464  	// query with integer with digit-count equals 7 and response received is also received
   465  	// with same digit-count and there is no float transformation
   466  	itr, err = db.ExecuteQuery("ns1", `{"selector":{"$and":[{"size":{"$eq": 1000007}}]}}`)
   467  	assert.NoError(t, err)
   468  
   469  	// verify one jerry result
   470  	queryResult1, err = itr.Next()
   471  	assert.NoError(t, err)
   472  	assert.NotNil(t, queryResult1)
   473  	versionedQueryRecord = queryResult1.(*statedb.VersionedKV)
   474  	stringRecord = string(versionedQueryRecord.Value)
   475  	bFoundRecord = strings.Contains(stringRecord, "joe")
   476  	assert.True(t, bFoundRecord)
   477  	bFoundRecord = strings.Contains(stringRecord, "1000007")
   478  	assert.True(t, bFoundRecord)
   479  
   480  	// verify no more results
   481  	queryResult2, err = itr.Next()
   482  	assert.NoError(t, err)
   483  	assert.Nil(t, queryResult2)
   484  
   485  }
   486  
   487  // TestGetVersion tests retrieving the version by namespace and key
   488  func TestGetVersion(t *testing.T, dbProvider statedb.VersionedDBProvider) {
   489  
   490  	db, err := dbProvider.GetDBHandle("testgetversion")
   491  	assert.NoError(t, err)
   492  
   493  	batch := statedb.NewUpdateBatch()
   494  	vv1 := statedb.VersionedValue{Value: []byte("value1"), Version: version.NewHeight(1, 1)}
   495  	vv2 := statedb.VersionedValue{Value: []byte("value2"), Version: version.NewHeight(1, 2)}
   496  	vv3 := statedb.VersionedValue{Value: []byte("value1"), Version: version.NewHeight(1, 3)}
   497  	vv4 := statedb.VersionedValue{Value: []byte("value2"), Version: version.NewHeight(1, 4)}
   498  
   499  	batch.Put("ns", "key1", vv1.Value, vv1.Version)
   500  	batch.Put("ns", "key2", vv2.Value, vv2.Version)
   501  	batch.Put("ns", "key3", vv2.Value, vv3.Version)
   502  	batch.Put("ns", "key4", vv2.Value, vv4.Version)
   503  	savePoint := version.NewHeight(1, 5)
   504  	err = db.ApplyUpdates(batch, savePoint)
   505  	assert.NoError(t, err)
   506  
   507  	//check to see if the bulk optimizable interface is supported (couchdb)
   508  	if bulkdb, ok := db.(statedb.BulkOptimizable); ok {
   509  		//clear the cached versions, this will force a read when getVerion is called
   510  		bulkdb.ClearCachedVersions()
   511  	}
   512  
   513  	//retrieve a version by namespace and key
   514  	resp, err := db.GetVersion("ns", "key2")
   515  	assert.NoError(t, err)
   516  	assert.Equal(t, version.NewHeight(1, 2), resp)
   517  
   518  	//attempt to retrieve an non-existent namespace and key
   519  	resp, err = db.GetVersion("ns2", "key2")
   520  	assert.NoError(t, err)
   521  	assert.Nil(t, resp)
   522  
   523  	//check to see if the bulk optimizable interface is supported (couchdb)
   524  	if bulkdb, ok := db.(statedb.BulkOptimizable); ok {
   525  
   526  		//clear the cached versions, this will force a read when getVerion is called
   527  		bulkdb.ClearCachedVersions()
   528  
   529  		// initialize a key list
   530  		loadKeys := []*statedb.CompositeKey{}
   531  		//create a composite key and add to the key list
   532  		compositeKey := statedb.CompositeKey{Namespace: "ns", Key: "key3"}
   533  		loadKeys = append(loadKeys, &compositeKey)
   534  		//load the committed versions
   535  		bulkdb.LoadCommittedVersions(loadKeys)
   536  
   537  		//retrieve a version by namespace and key
   538  		resp, err := db.GetVersion("ns", "key3")
   539  		assert.NoError(t, err)
   540  		assert.Equal(t, version.NewHeight(1, 3), resp)
   541  
   542  	}
   543  }
   544  
   545  // TestSmallBatchSize tests multiple update batches
   546  func TestSmallBatchSize(t *testing.T, dbProvider statedb.VersionedDBProvider) {
   547  	db, err := dbProvider.GetDBHandle("testsmallbatchsize")
   548  	assert.NoError(t, err)
   549  	db.Open()
   550  	defer db.Close()
   551  	batch := statedb.NewUpdateBatch()
   552  	jsonValue1 := []byte(`{"asset_name": "marble1","color": "blue","size": 1,"owner": "tom"}`)
   553  	batch.Put("ns1", "key1", jsonValue1, version.NewHeight(1, 1))
   554  	jsonValue2 := []byte(`{"asset_name": "marble2","color": "blue","size": 2,"owner": "jerry"}`)
   555  	batch.Put("ns1", "key2", jsonValue2, version.NewHeight(1, 2))
   556  	jsonValue3 := []byte(`{"asset_name": "marble3","color": "blue","size": 3,"owner": "fred"}`)
   557  	batch.Put("ns1", "key3", jsonValue3, version.NewHeight(1, 3))
   558  	jsonValue4 := []byte(`{"asset_name": "marble4","color": "blue","size": 4,"owner": "martha"}`)
   559  	batch.Put("ns1", "key4", jsonValue4, version.NewHeight(1, 4))
   560  	jsonValue5 := []byte(`{"asset_name": "marble5","color": "blue","size": 5,"owner": "fred"}`)
   561  	batch.Put("ns1", "key5", jsonValue5, version.NewHeight(1, 5))
   562  	jsonValue6 := []byte(`{"asset_name": "marble6","color": "blue","size": 6,"owner": "elaine"}`)
   563  	batch.Put("ns1", "key6", jsonValue6, version.NewHeight(1, 6))
   564  	jsonValue7 := []byte(`{"asset_name": "marble7","color": "blue","size": 7,"owner": "fred"}`)
   565  	batch.Put("ns1", "key7", jsonValue7, version.NewHeight(1, 7))
   566  	jsonValue8 := []byte(`{"asset_name": "marble8","color": "blue","size": 8,"owner": "elaine"}`)
   567  	batch.Put("ns1", "key8", jsonValue8, version.NewHeight(1, 8))
   568  	jsonValue9 := []byte(`{"asset_name": "marble9","color": "green","size": 9,"owner": "fred"}`)
   569  	batch.Put("ns1", "key9", jsonValue9, version.NewHeight(1, 9))
   570  	jsonValue10 := []byte(`{"asset_name": "marble10","color": "green","size": 10,"owner": "mary"}`)
   571  	batch.Put("ns1", "key10", jsonValue10, version.NewHeight(1, 10))
   572  	jsonValue11 := []byte(`{"asset_name": "marble11","color": "cyan","size": 1000007,"owner": "joe"}`)
   573  	batch.Put("ns1", "key11", jsonValue11, version.NewHeight(1, 11))
   574  
   575  	savePoint := version.NewHeight(1, 12)
   576  	db.ApplyUpdates(batch, savePoint)
   577  
   578  	//Verify all marbles were added
   579  
   580  	vv, _ := db.GetState("ns1", "key1")
   581  	assert.JSONEq(t, string(jsonValue1), string(vv.Value))
   582  
   583  	vv, _ = db.GetState("ns1", "key2")
   584  	assert.JSONEq(t, string(jsonValue2), string(vv.Value))
   585  
   586  	vv, _ = db.GetState("ns1", "key3")
   587  	assert.JSONEq(t, string(jsonValue3), string(vv.Value))
   588  
   589  	vv, _ = db.GetState("ns1", "key4")
   590  	assert.JSONEq(t, string(jsonValue4), string(vv.Value))
   591  
   592  	vv, _ = db.GetState("ns1", "key5")
   593  	assert.JSONEq(t, string(jsonValue5), string(vv.Value))
   594  
   595  	vv, _ = db.GetState("ns1", "key6")
   596  	assert.JSONEq(t, string(jsonValue6), string(vv.Value))
   597  
   598  	vv, _ = db.GetState("ns1", "key7")
   599  	assert.JSONEq(t, string(jsonValue7), string(vv.Value))
   600  
   601  	vv, _ = db.GetState("ns1", "key8")
   602  	assert.JSONEq(t, string(jsonValue8), string(vv.Value))
   603  
   604  	vv, _ = db.GetState("ns1", "key9")
   605  	assert.JSONEq(t, string(jsonValue9), string(vv.Value))
   606  
   607  	vv, _ = db.GetState("ns1", "key10")
   608  	assert.JSONEq(t, string(jsonValue10), string(vv.Value))
   609  
   610  	vv, _ = db.GetState("ns1", "key11")
   611  	assert.JSONEq(t, string(jsonValue11), string(vv.Value))
   612  }
   613  
   614  // TestBatchWithIndividualRetry tests a single failure in a batch
   615  func TestBatchWithIndividualRetry(t *testing.T, dbProvider statedb.VersionedDBProvider) {
   616  
   617  	db, err := dbProvider.GetDBHandle("testbatchretry")
   618  	assert.NoError(t, err)
   619  
   620  	batch := statedb.NewUpdateBatch()
   621  	vv1 := statedb.VersionedValue{Value: []byte("value1"), Version: version.NewHeight(1, 1)}
   622  	vv2 := statedb.VersionedValue{Value: []byte("value2"), Version: version.NewHeight(1, 2)}
   623  	vv3 := statedb.VersionedValue{Value: []byte("value3"), Version: version.NewHeight(1, 3)}
   624  	vv4 := statedb.VersionedValue{Value: []byte("value4"), Version: version.NewHeight(1, 4)}
   625  
   626  	batch.Put("ns", "key1", vv1.Value, vv1.Version)
   627  	batch.Put("ns", "key2", vv2.Value, vv2.Version)
   628  	batch.Put("ns", "key3", vv3.Value, vv3.Version)
   629  	batch.Put("ns", "key4", vv4.Value, vv4.Version)
   630  	savePoint := version.NewHeight(1, 5)
   631  	err = db.ApplyUpdates(batch, savePoint)
   632  	assert.NoError(t, err)
   633  
   634  	// Clear the cache for the next batch, in place of simulation
   635  	if bulkdb, ok := db.(statedb.BulkOptimizable); ok {
   636  		//clear the cached versions, this will force a read when getVerion is called
   637  		bulkdb.ClearCachedVersions()
   638  	}
   639  
   640  	batch = statedb.NewUpdateBatch()
   641  	batch.Put("ns", "key1", vv1.Value, vv1.Version)
   642  	batch.Put("ns", "key2", vv2.Value, vv2.Version)
   643  	batch.Put("ns", "key3", vv3.Value, vv3.Version)
   644  	batch.Put("ns", "key4", vv4.Value, vv4.Version)
   645  	savePoint = version.NewHeight(1, 6)
   646  	err = db.ApplyUpdates(batch, savePoint)
   647  	assert.NoError(t, err)
   648  
   649  	// Update document key3
   650  	batch = statedb.NewUpdateBatch()
   651  	batch.Delete("ns", "key2", vv2.Version)
   652  	batch.Put("ns", "key3", vv3.Value, vv3.Version)
   653  	savePoint = version.NewHeight(1, 7)
   654  	err = db.ApplyUpdates(batch, savePoint)
   655  	assert.NoError(t, err)
   656  
   657  	// This should force a retry for couchdb revision conflict for both delete and update
   658  	// Retry logic should correct the update and prevent delete from throwing an error
   659  	batch = statedb.NewUpdateBatch()
   660  	batch.Delete("ns", "key2", vv2.Version)
   661  	batch.Put("ns", "key3", vv3.Value, vv3.Version)
   662  	savePoint = version.NewHeight(1, 8)
   663  	err = db.ApplyUpdates(batch, savePoint)
   664  	assert.NoError(t, err)
   665  
   666  	//Create a new set of values that use JSONs instead of binary
   667  	jsonValue5 := []byte(`{"asset_name": "marble5","color": "blue","size": 5,"owner": "fred"}`)
   668  	jsonValue6 := []byte(`{"asset_name": "marble6","color": "blue","size": 6,"owner": "elaine"}`)
   669  	jsonValue7 := []byte(`{"asset_name": "marble7","color": "blue","size": 7,"owner": "fred"}`)
   670  	jsonValue8 := []byte(`{"asset_name": "marble8","color": "blue","size": 8,"owner": "elaine"}`)
   671  
   672  	// Clear the cache for the next batch, in place of simulation
   673  	if bulkdb, ok := db.(statedb.BulkOptimizable); ok {
   674  		//clear the cached versions, this will force a read when getVersion is called
   675  		bulkdb.ClearCachedVersions()
   676  	}
   677  
   678  	batch = statedb.NewUpdateBatch()
   679  	batch.Put("ns1", "key5", jsonValue5, version.NewHeight(1, 9))
   680  	batch.Put("ns1", "key6", jsonValue6, version.NewHeight(1, 10))
   681  	batch.Put("ns1", "key7", jsonValue7, version.NewHeight(1, 11))
   682  	batch.Put("ns1", "key8", jsonValue8, version.NewHeight(1, 12))
   683  	savePoint = version.NewHeight(1, 6)
   684  	err = db.ApplyUpdates(batch, savePoint)
   685  	assert.NoError(t, err)
   686  
   687  	// Clear the cache for the next batch, in place of simulation
   688  	if bulkdb, ok := db.(statedb.BulkOptimizable); ok {
   689  		//clear the cached versions, this will force a read when getVersion is called
   690  		bulkdb.ClearCachedVersions()
   691  	}
   692  
   693  	//Send the batch through again to test updates
   694  	batch = statedb.NewUpdateBatch()
   695  	batch.Put("ns1", "key5", jsonValue5, version.NewHeight(1, 9))
   696  	batch.Put("ns1", "key6", jsonValue6, version.NewHeight(1, 10))
   697  	batch.Put("ns1", "key7", jsonValue7, version.NewHeight(1, 11))
   698  	batch.Put("ns1", "key8", jsonValue8, version.NewHeight(1, 12))
   699  	savePoint = version.NewHeight(1, 6)
   700  	err = db.ApplyUpdates(batch, savePoint)
   701  	assert.NoError(t, err)
   702  
   703  	// Update document key3
   704  	// this will cause an inconsistent cache entry for connection db2
   705  	batch = statedb.NewUpdateBatch()
   706  	batch.Delete("ns1", "key6", version.NewHeight(1, 13))
   707  	batch.Put("ns1", "key7", jsonValue7, version.NewHeight(1, 14))
   708  	savePoint = version.NewHeight(1, 15)
   709  	err = db.ApplyUpdates(batch, savePoint)
   710  	assert.NoError(t, err)
   711  
   712  	// This should force a retry for couchdb revision conflict for both delete and update
   713  	// Retry logic should correct the update and prevent delete from throwing an error
   714  	batch = statedb.NewUpdateBatch()
   715  	batch.Delete("ns1", "key6", version.NewHeight(1, 16))
   716  	batch.Put("ns1", "key7", jsonValue7, version.NewHeight(1, 17))
   717  	savePoint = version.NewHeight(1, 18)
   718  	err = db.ApplyUpdates(batch, savePoint)
   719  	assert.NoError(t, err)
   720  
   721  }
   722  
   723  // TestValueAndMetadataWrites tests statedb for value and metadata read-writes
   724  func TestValueAndMetadataWrites(t *testing.T, dbProvider statedb.VersionedDBProvider) {
   725  	db, err := dbProvider.GetDBHandle("testvalueandmetadata")
   726  	assert.NoError(t, err)
   727  	batch := statedb.NewUpdateBatch()
   728  
   729  	vv1 := statedb.VersionedValue{Value: []byte("value1"), Metadata: []byte("metadata1"), Version: version.NewHeight(1, 1)}
   730  	vv2 := statedb.VersionedValue{Value: []byte("value2"), Metadata: []byte("metadata2"), Version: version.NewHeight(1, 2)}
   731  	vv3 := statedb.VersionedValue{Value: []byte("value3"), Version: version.NewHeight(1, 3)}
   732  	vv4 := statedb.VersionedValue{Value: []byte{}, Metadata: []byte("metadata4"), Version: version.NewHeight(1, 4)}
   733  
   734  	batch.PutValAndMetadata("ns1", "key1", vv1.Value, vv1.Metadata, vv1.Version)
   735  	batch.PutValAndMetadata("ns1", "key2", vv2.Value, vv2.Metadata, vv2.Version)
   736  	batch.PutValAndMetadata("ns2", "key3", vv3.Value, vv3.Metadata, vv3.Version)
   737  	batch.PutValAndMetadata("ns2", "key4", vv4.Value, vv4.Metadata, vv4.Version)
   738  	db.ApplyUpdates(batch, version.NewHeight(2, 5))
   739  
   740  	vv, _ := db.GetState("ns1", "key1")
   741  	assert.Equal(t, &vv1, vv)
   742  
   743  	vv, _ = db.GetState("ns1", "key2")
   744  	assert.Equal(t, &vv2, vv)
   745  
   746  	vv, _ = db.GetState("ns2", "key3")
   747  	assert.Equal(t, &vv3, vv)
   748  
   749  	vv, _ = db.GetState("ns2", "key4")
   750  	assert.Equal(t, &vv4, vv)
   751  }
   752  
   753  // TestPaginatedRangeQuery tests range queries with pagination
   754  func TestPaginatedRangeQuery(t *testing.T, dbProvider statedb.VersionedDBProvider) {
   755  	db, err := dbProvider.GetDBHandle("testpaginatedrangequery")
   756  	assert.NoError(t, err)
   757  	db.Open()
   758  	defer db.Close()
   759  	batch := statedb.NewUpdateBatch()
   760  	jsonValue1 := `{"asset_name": "marble1","color": "blue","size": 1,"owner": "tom"}`
   761  	batch.Put("ns1", "key1", []byte(jsonValue1), version.NewHeight(1, 1))
   762  	jsonValue2 := `{"asset_name": "marble2","color": "red","size": 2,"owner": "jerry"}`
   763  	batch.Put("ns1", "key2", []byte(jsonValue2), version.NewHeight(1, 2))
   764  	jsonValue3 := `{"asset_name": "marble3","color": "red","size": 3,"owner": "fred"}`
   765  	batch.Put("ns1", "key3", []byte(jsonValue3), version.NewHeight(1, 3))
   766  	jsonValue4 := `{"asset_name": "marble4","color": "red","size": 4,"owner": "martha"}`
   767  	batch.Put("ns1", "key4", []byte(jsonValue4), version.NewHeight(1, 4))
   768  	jsonValue5 := `{"asset_name": "marble5","color": "blue","size": 5,"owner": "fred"}`
   769  	batch.Put("ns1", "key5", []byte(jsonValue5), version.NewHeight(1, 5))
   770  	jsonValue6 := `{"asset_name": "marble6","color": "red","size": 6,"owner": "elaine"}`
   771  	batch.Put("ns1", "key6", []byte(jsonValue6), version.NewHeight(1, 6))
   772  	jsonValue7 := `{"asset_name": "marble7","color": "blue","size": 7,"owner": "fred"}`
   773  	batch.Put("ns1", "key7", []byte(jsonValue7), version.NewHeight(1, 7))
   774  	jsonValue8 := `{"asset_name": "marble8","color": "red","size": 8,"owner": "elaine"}`
   775  	batch.Put("ns1", "key8", []byte(jsonValue8), version.NewHeight(1, 8))
   776  	jsonValue9 := `{"asset_name": "marble9","color": "green","size": 9,"owner": "fred"}`
   777  	batch.Put("ns1", "key9", []byte(jsonValue9), version.NewHeight(1, 9))
   778  	jsonValue10 := `{"asset_name": "marble10","color": "green","size": 10,"owner": "mary"}`
   779  	batch.Put("ns1", "key10", []byte(jsonValue10), version.NewHeight(1, 10))
   780  
   781  	jsonValue11 := `{"asset_name": "marble11","color": "cyan","size": 8,"owner": "joe"}`
   782  	batch.Put("ns1", "key11", []byte(jsonValue11), version.NewHeight(1, 11))
   783  	jsonValue12 := `{"asset_name": "marble12","color": "red","size": 4,"owner": "martha"}`
   784  	batch.Put("ns1", "key12", []byte(jsonValue12), version.NewHeight(1, 4))
   785  	jsonValue13 := `{"asset_name": "marble13","color": "red","size": 6,"owner": "james"}`
   786  	batch.Put("ns1", "key13", []byte(jsonValue13), version.NewHeight(1, 4))
   787  	jsonValue14 := `{"asset_name": "marble14","color": "red","size": 10,"owner": "fred"}`
   788  	batch.Put("ns1", "key14", []byte(jsonValue14), version.NewHeight(1, 4))
   789  	jsonValue15 := `{"asset_name": "marble15","color": "red","size": 8,"owner": "mary"}`
   790  	batch.Put("ns1", "key15", []byte(jsonValue15), version.NewHeight(1, 4))
   791  	jsonValue16 := `{"asset_name": "marble16","color": "red","size": 4,"owner": "robert"}`
   792  	batch.Put("ns1", "key16", []byte(jsonValue16), version.NewHeight(1, 4))
   793  	jsonValue17 := `{"asset_name": "marble17","color": "red","size": 2,"owner": "alan"}`
   794  	batch.Put("ns1", "key17", []byte(jsonValue17), version.NewHeight(1, 4))
   795  	jsonValue18 := `{"asset_name": "marble18","color": "red","size": 10,"owner": "elaine"}`
   796  	batch.Put("ns1", "key18", []byte(jsonValue18), version.NewHeight(1, 4))
   797  	jsonValue19 := `{"asset_name": "marble19","color": "red","size": 2,"owner": "alan"}`
   798  	batch.Put("ns1", "key19", []byte(jsonValue19), version.NewHeight(1, 4))
   799  	jsonValue20 := `{"asset_name": "marble20","color": "red","size": 10,"owner": "elaine"}`
   800  	batch.Put("ns1", "key20", []byte(jsonValue20), version.NewHeight(1, 4))
   801  
   802  	jsonValue21 := `{"asset_name": "marble21","color": "cyan","size": 1000007,"owner": "joe"}`
   803  	batch.Put("ns1", "key21", []byte(jsonValue21), version.NewHeight(1, 11))
   804  	jsonValue22 := `{"asset_name": "marble22","color": "red","size": 4,"owner": "martha"}`
   805  	batch.Put("ns1", "key22", []byte(jsonValue22), version.NewHeight(1, 4))
   806  	jsonValue23 := `{"asset_name": "marble23","color": "blue","size": 6,"owner": "james"}`
   807  	batch.Put("ns1", "key23", []byte(jsonValue23), version.NewHeight(1, 4))
   808  	jsonValue24 := `{"asset_name": "marble24","color": "red","size": 10,"owner": "fred"}`
   809  	batch.Put("ns1", "key24", []byte(jsonValue24), version.NewHeight(1, 4))
   810  	jsonValue25 := `{"asset_name": "marble25","color": "red","size": 8,"owner": "mary"}`
   811  	batch.Put("ns1", "key25", []byte(jsonValue25), version.NewHeight(1, 4))
   812  	jsonValue26 := `{"asset_name": "marble26","color": "red","size": 4,"owner": "robert"}`
   813  	batch.Put("ns1", "key26", []byte(jsonValue26), version.NewHeight(1, 4))
   814  	jsonValue27 := `{"asset_name": "marble27","color": "green","size": 2,"owner": "alan"}`
   815  	batch.Put("ns1", "key27", []byte(jsonValue27), version.NewHeight(1, 4))
   816  	jsonValue28 := `{"asset_name": "marble28","color": "red","size": 10,"owner": "elaine"}`
   817  	batch.Put("ns1", "key28", []byte(jsonValue28), version.NewHeight(1, 4))
   818  	jsonValue29 := `{"asset_name": "marble29","color": "red","size": 2,"owner": "alan"}`
   819  	batch.Put("ns1", "key29", []byte(jsonValue29), version.NewHeight(1, 4))
   820  	jsonValue30 := `{"asset_name": "marble30","color": "red","size": 10,"owner": "elaine"}`
   821  	batch.Put("ns1", "key30", []byte(jsonValue30), version.NewHeight(1, 4))
   822  
   823  	jsonValue31 := `{"asset_name": "marble31","color": "cyan","size": 1000007,"owner": "joe"}`
   824  	batch.Put("ns1", "key31", []byte(jsonValue31), version.NewHeight(1, 11))
   825  	jsonValue32 := `{"asset_name": "marble32","color": "red","size": 4,"owner": "martha"}`
   826  	batch.Put("ns1", "key32", []byte(jsonValue32), version.NewHeight(1, 4))
   827  	jsonValue33 := `{"asset_name": "marble33","color": "red","size": 6,"owner": "james"}`
   828  	batch.Put("ns1", "key33", []byte(jsonValue33), version.NewHeight(1, 4))
   829  	jsonValue34 := `{"asset_name": "marble34","color": "red","size": 10,"owner": "fred"}`
   830  	batch.Put("ns1", "key34", []byte(jsonValue34), version.NewHeight(1, 4))
   831  	jsonValue35 := `{"asset_name": "marble35","color": "red","size": 8,"owner": "mary"}`
   832  	batch.Put("ns1", "key35", []byte(jsonValue35), version.NewHeight(1, 4))
   833  	jsonValue36 := `{"asset_name": "marble36","color": "orange","size": 4,"owner": "robert"}`
   834  	batch.Put("ns1", "key36", []byte(jsonValue36), version.NewHeight(1, 4))
   835  	jsonValue37 := `{"asset_name": "marble37","color": "red","size": 2,"owner": "alan"}`
   836  	batch.Put("ns1", "key37", []byte(jsonValue37), version.NewHeight(1, 4))
   837  	jsonValue38 := `{"asset_name": "marble38","color": "yellow","size": 10,"owner": "elaine"}`
   838  	batch.Put("ns1", "key38", []byte(jsonValue38), version.NewHeight(1, 4))
   839  	jsonValue39 := `{"asset_name": "marble39","color": "red","size": 2,"owner": "alan"}`
   840  	batch.Put("ns1", "key39", []byte(jsonValue39), version.NewHeight(1, 4))
   841  	jsonValue40 := `{"asset_name": "marble40","color": "red","size": 10,"owner": "elaine"}`
   842  	batch.Put("ns1", "key40", []byte(jsonValue40), version.NewHeight(1, 4))
   843  
   844  	savePoint := version.NewHeight(2, 22)
   845  	db.ApplyUpdates(batch, savePoint)
   846  
   847  	//Test range query with no pagination
   848  	returnKeys := []string{}
   849  	_, err = executeRangeQuery(t, db, "ns1", "key1", "key15", int32(0), returnKeys)
   850  	assert.NoError(t, err)
   851  
   852  	//Test range query with large page size (single page return)
   853  	returnKeys = []string{"key1", "key10", "key11", "key12", "key13", "key14"}
   854  	_, err = executeRangeQuery(t, db, "ns1", "key1", "key15", int32(10), returnKeys)
   855  	assert.NoError(t, err)
   856  
   857  	//Test explicit pagination
   858  	//Test range query with multiple pages
   859  	returnKeys = []string{"key1", "key10"}
   860  	nextStartKey, err := executeRangeQuery(t, db, "ns1", "key1", "key22", int32(2), returnKeys)
   861  	assert.NoError(t, err)
   862  
   863  	// NextStartKey is now passed in as startKey,  verify the pagesize is working
   864  	returnKeys = []string{"key11", "key12"}
   865  	_, err = executeRangeQuery(t, db, "ns1", nextStartKey, "key22", int32(2), returnKeys)
   866  	assert.NoError(t, err)
   867  
   868  	//Test implicit pagination
   869  	//Test range query with no pagesize and a small queryLimit
   870  	returnKeys = []string{}
   871  	_, err = executeRangeQuery(t, db, "ns1", "key1", "key15", int32(0), returnKeys)
   872  	assert.NoError(t, err)
   873  
   874  	//Test range query with pagesize greater than the queryLimit
   875  	returnKeys = []string{"key1", "key10", "key11", "key12"}
   876  	_, err = executeRangeQuery(t, db, "ns1", "key1", "key15", int32(4), returnKeys)
   877  	assert.NoError(t, err)
   878  }
   879  
   880  // TestRangeQuerySpecialCharacters tests range queries for keys with special characters and/or non-English characters
   881  func TestRangeQuerySpecialCharacters(t *testing.T, dbProvider statedb.VersionedDBProvider) {
   882  	db, err := dbProvider.GetDBHandle("testrangequeryspecialcharacters")
   883  	assert.NoError(t, err)
   884  	db.Open()
   885  	defer db.Close()
   886  
   887  	batch := statedb.NewUpdateBatch()
   888  	jsonValue1 := `{"asset_name": "marble1","color": "blue","size": 1,"owner": "tom"}`
   889  	batch.Put("ns1", "key1", []byte(jsonValue1), version.NewHeight(1, 1))
   890  	jsonValue2 := `{"asset_name": "marble2","color": "red","size": 2,"owner": "jerry"}`
   891  	batch.Put("ns1", "key2", []byte(jsonValue2), version.NewHeight(1, 1))
   892  	jsonValue3 := `{"asset_name": "marble3","color": "red","size": 2,"owner": "jerry"}`
   893  	batch.Put("ns1", "key1&%-", []byte(jsonValue3), version.NewHeight(1, 1))
   894  	jsonValue4 := `{"asset_name": "marble4","color": "red","size": 4,"owner": "martha"}`
   895  	batch.Put("ns1", "key1-a", []byte(jsonValue4), version.NewHeight(1, 4))
   896  	jsonValue5 := `{"asset_name": "marble5","color": "red","size": 2,"owner": "jerry"}`
   897  	batch.Put("ns1", "key1%=", []byte(jsonValue5), version.NewHeight(1, 2))
   898  	jsonValue6 := `{"asset_name": "marble6","color": "red","size": 3,"owner": "fred"}`
   899  	batch.Put("ns1", "key1español", []byte(jsonValue6), version.NewHeight(1, 3))
   900  	jsonValue7 := `{"asset_name": "marble7","color": "blue","size": 5,"owner": "fred"}`
   901  	batch.Put("ns1", "key1中文", []byte(jsonValue7), version.NewHeight(1, 5))
   902  	jsonValue8 := `{"asset_name": "marble8","color": "blue","size": 7,"owner": "fred"}`
   903  	batch.Put("ns1", "key1한국어", []byte(jsonValue8), version.NewHeight(1, 7))
   904  	jsonValue9 := `{"asset_name": "marble9","color": "blue","size": 5,"owner": "fred"}`
   905  	batch.Put("ns1", "中文key1", []byte(jsonValue9), version.NewHeight(1, 5))
   906  	jsonValue10 := `{"asset_name": "marble10","color": "green","size": 10,"owner": "mary"}`
   907  	batch.Put("ns1", "key10", []byte(jsonValue10), version.NewHeight(1, 10))
   908  	jsonValue11 := `{"asset_name": "marble11","color": "cyan","size": 8,"owner": "joe"}`
   909  	batch.Put("ns1", "key1z", []byte(jsonValue11), version.NewHeight(1, 11))
   910  
   911  	savePoint := version.NewHeight(2, 22)
   912  	db.ApplyUpdates(batch, savePoint)
   913  
   914  	//Test range query for the keys with special or non-English characters
   915  	returnKeys := []string{"key1", "key1%=", "key1&%-", "key1-a", "key10", "key1español", "key1z", "key1中文", "key1한국어"}
   916  	// returnKeys := []string{"key1", "key1%=", "key1&%-", "key1-a", "key10", "key1español", "key1z"}
   917  	_, err = executeRangeQuery(t, db, "ns1", "key1", "key2", int32(10), returnKeys)
   918  	assert.NoError(t, err)
   919  }
   920  
   921  func executeRangeQuery(t *testing.T, db statedb.VersionedDB, namespace, startKey, endKey string, limit int32, returnKeys []string) (string, error) {
   922  
   923  	var itr statedb.ResultsIterator
   924  	var err error
   925  
   926  	if limit == 0 {
   927  
   928  		itr, err = db.GetStateRangeScanIterator(namespace, startKey, endKey)
   929  		if err != nil {
   930  			return "", err
   931  		}
   932  
   933  	} else {
   934  
   935  		queryOptions := make(map[string]interface{})
   936  		if limit != 0 {
   937  			queryOptions["limit"] = limit
   938  		}
   939  		itr, err = db.GetStateRangeScanIteratorWithMetadata(namespace, startKey, endKey, queryOptions)
   940  		if err != nil {
   941  			return "", err
   942  		}
   943  
   944  		// Verify the keys returned
   945  		if limit > 0 {
   946  			TestItrWithoutClose(t, itr, returnKeys)
   947  		}
   948  
   949  	}
   950  
   951  	returnBookmark := ""
   952  	if limit > 0 {
   953  		if queryResultItr, ok := itr.(statedb.QueryResultsIterator); ok {
   954  			returnBookmark = queryResultItr.GetBookmarkAndClose()
   955  		}
   956  	}
   957  
   958  	return returnBookmark, nil
   959  }
   960  
   961  // TestItrWithoutClose verifies an iterator contains expected keys
   962  func TestItrWithoutClose(t *testing.T, itr statedb.ResultsIterator, expectedKeys []string) {
   963  	for _, expectedKey := range expectedKeys {
   964  		queryResult, err := itr.Next()
   965  		assert.NoError(t, err, "An unexpected error was thrown during iterator Next()")
   966  		vkv := queryResult.(*statedb.VersionedKV)
   967  		key := vkv.Key
   968  		assert.Equal(t, expectedKey, key)
   969  	}
   970  	queryResult, err := itr.Next()
   971  	assert.NoError(t, err, "An unexpected error was thrown during iterator Next()")
   972  	assert.Nil(t, queryResult)
   973  }
   974  
   975  func TestApplyUpdatesWithNilHeight(t *testing.T, dbProvider statedb.VersionedDBProvider) {
   976  	db, err := dbProvider.GetDBHandle("test-apply-updates-with-nil-height")
   977  	assert.NoError(t, err)
   978  
   979  	batch1 := statedb.NewUpdateBatch()
   980  	batch1.Put("ns", "key1", []byte("value1"), version.NewHeight(1, 4))
   981  	savePoint := version.NewHeight(1, 5)
   982  	assert.NoError(t, db.ApplyUpdates(batch1, savePoint))
   983  
   984  	batch2 := statedb.NewUpdateBatch()
   985  	batch2.Put("ns", "key1", []byte("value2"), version.NewHeight(1, 1))
   986  	assert.NoError(t, db.ApplyUpdates(batch2, nil))
   987  
   988  	ht, err := db.GetLatestSavePoint()
   989  	assert.NoError(t, err)
   990  	assert.Equal(t, savePoint, ht) // savepoint should still be what was set with batch1
   991  	// (because batch2 calls ApplyUpdates with savepoint as nil)
   992  }