github.com/renegr87/renegr87@v2.1.1+incompatible/core/ledger/kvledger/txmgmt/statedb/statecouchdb/commit_handling_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  	"strconv"
    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  func TestGetRevision(t *testing.T) {
    19  	env := testEnv
    20  	env.init(t, &statedb.Cache{})
    21  	defer env.cleanup()
    22  
    23  	versionedDB, err := testEnv.DBProvider.GetDBHandle("test-get-revisions")
    24  	assert.NoError(t, err)
    25  	db := versionedDB.(*VersionedDB)
    26  
    27  	// initializing data in couchdb
    28  	batch := statedb.NewUpdateBatch()
    29  	batch.Put("ns", "key-in-db", []byte("value1"), version.NewHeight(1, 1))
    30  	batch.Put("ns", "key-in-both-db-cache", []byte("value2"), version.NewHeight(1, 2))
    31  	savePoint := version.NewHeight(1, 2)
    32  	assert.NoError(t, db.ApplyUpdates(batch, savePoint))
    33  
    34  	// load revision cache with couchDB revision number.
    35  	keys := []*statedb.CompositeKey{
    36  		{
    37  			Namespace: "ns",
    38  			Key:       "key-in-both-db-cache",
    39  		},
    40  	}
    41  	db.LoadCommittedVersions(keys)
    42  	// change cache reivision number for test purpose. (makes sure only read from cache but not db)
    43  	db.committedDataCache.setVerAndRev("ns", "key-in-both-db-cache", version.NewHeight(1, 2), "revision-db-number")
    44  
    45  	// Set test revision number only in cache, but not in db.
    46  	db.committedDataCache.setVerAndRev("ns", "key-in-cache", version.NewHeight(1, 1), "revision-cache-number")
    47  
    48  	nsUpdates := map[string]*statedb.VersionedValue{
    49  		"key-in-cache": {
    50  			Value:    []byte("test-value"),
    51  			Metadata: nil,
    52  			Version:  version.NewHeight(1, 1),
    53  		},
    54  		"key-in-db": {
    55  			Value:    []byte("value3"),
    56  			Metadata: nil,
    57  			Version:  version.NewHeight(1, 1),
    58  		},
    59  		"key-in-both-db-cache": {
    60  			Value:    []byte("value4"),
    61  			Metadata: nil,
    62  			Version:  version.NewHeight(1, 2),
    63  		},
    64  		"bad-key": {
    65  			Value:    []byte("bad-key-value"),
    66  			Metadata: nil,
    67  			Version:  version.NewHeight(1, 5),
    68  		},
    69  	}
    70  
    71  	revisionsMap, err := db.getRevisions("ns", nsUpdates)
    72  	assert.NoError(t, err)
    73  	assert.Equal(t, "revision-cache-number", revisionsMap["key-in-cache"])
    74  	assert.NotEqual(t, "", revisionsMap["key-in-db"])
    75  	assert.Equal(t, "revision-db-number", revisionsMap["key-in-both-db-cache"])
    76  	assert.Equal(t, "", revisionsMap["bad-key"])
    77  
    78  	// Get revisions of non-existing nameSpace.
    79  	revisionsMap, err = db.getRevisions("bad-namespace", nsUpdates)
    80  	assert.NoError(t, err)
    81  	assert.Equal(t, "", revisionsMap["key-in-db"])
    82  
    83  }
    84  
    85  func TestBuildCommittersForNs(t *testing.T) {
    86  	env := testEnv
    87  	env.init(t, &statedb.Cache{})
    88  	defer env.cleanup()
    89  
    90  	versionedDB, err := testEnv.DBProvider.GetDBHandle("test-build-committers-for-ns")
    91  	assert.NoError(t, err)
    92  	db := versionedDB.(*VersionedDB)
    93  
    94  	nsUpdates := map[string]*statedb.VersionedValue{
    95  		"bad-key": {},
    96  	}
    97  
    98  	_, err = db.buildCommittersForNs("ns", nsUpdates)
    99  	assert.EqualError(t, err, "nil version not supported")
   100  
   101  	nsUpdates = make(map[string]*statedb.VersionedValue)
   102  	// populate updates with maxBatchSize + 1.
   103  	dummyHeight := version.NewHeight(1, 1)
   104  	for i := 0; i <= env.config.MaxBatchUpdateSize; i++ {
   105  		nsUpdates[strconv.Itoa(i)] = &statedb.VersionedValue{
   106  			Value:    nil,
   107  			Metadata: nil,
   108  			Version:  dummyHeight,
   109  		}
   110  	}
   111  
   112  	committers, err := db.buildCommittersForNs("ns", nsUpdates)
   113  	assert.NoError(t, err)
   114  	assert.Equal(t, 2, len(committers))
   115  	assert.Equal(t, "ns", committers[0].namespace)
   116  	assert.Equal(t, "ns", committers[1].namespace)
   117  
   118  }
   119  
   120  func TestBuildCommitters(t *testing.T) {
   121  	env := testEnv
   122  	env.init(t, &statedb.Cache{})
   123  	defer env.cleanup()
   124  
   125  	versionedDB, err := testEnv.DBProvider.GetDBHandle("test-build-committers")
   126  	assert.NoError(t, err)
   127  	db := versionedDB.(*VersionedDB)
   128  
   129  	dummyHeight := version.NewHeight(1, 1)
   130  	batch := statedb.NewUpdateBatch()
   131  	batch.Put("ns-1", "key1", []byte("value1"), dummyHeight)
   132  	batch.Put("ns-2", "key1", []byte("value2"), dummyHeight)
   133  	for i := 0; i <= env.config.MaxBatchUpdateSize; i++ {
   134  		batch.Put("maxBatch", "key1", []byte("value3"), dummyHeight)
   135  	}
   136  	namespaceSet := map[string]bool{
   137  		"ns-1": true, "ns-2": true, "maxBatch": true,
   138  	}
   139  
   140  	committer, err := db.buildCommitters(batch)
   141  	assert.NoError(t, err)
   142  	assert.Equal(t, 3, len(committer))
   143  	for _, commit := range committer {
   144  		assert.True(t, namespaceSet[commit.namespace])
   145  	}
   146  
   147  	badBatch := statedb.NewUpdateBatch()
   148  	badBatch.Put("bad-ns", "bad-key", []byte("bad-value"), nil)
   149  
   150  	committer, err = db.buildCommitters(badBatch)
   151  	assert.EqualError(t, err, "nil version not supported")
   152  }
   153  
   154  func TestExecuteCommitter(t *testing.T) {
   155  	env := testEnv
   156  	env.init(t, &statedb.Cache{})
   157  	defer env.cleanup()
   158  
   159  	versionedDB, err := testEnv.DBProvider.GetDBHandle("test-execute-committer")
   160  	assert.NoError(t, err)
   161  	db := versionedDB.(*VersionedDB)
   162  
   163  	committerDB, err := db.getNamespaceDBHandle("ns")
   164  	assert.NoError(t, err)
   165  	couchDocKey1, err := keyValToCouchDoc(&keyValue{
   166  		key:            "key1",
   167  		revision:       "",
   168  		VersionedValue: &statedb.VersionedValue{Value: []byte("value1"), Metadata: nil, Version: version.NewHeight(1, 1)},
   169  	})
   170  	assert.NoError(t, err)
   171  	couchDocKey2, err := keyValToCouchDoc(&keyValue{
   172  		key:            "key2",
   173  		revision:       "",
   174  		VersionedValue: &statedb.VersionedValue{Value: nil, Metadata: nil, Version: version.NewHeight(1, 1)},
   175  	})
   176  	assert.NoError(t, err)
   177  
   178  	committers := []*committer{
   179  		{
   180  			db:             committerDB,
   181  			batchUpdateMap: map[string]*batchableDocument{"key1": {CouchDoc: *couchDocKey1}},
   182  			namespace:      "ns",
   183  			cacheKVs:       make(statedb.CacheKVs),
   184  			cacheEnabled:   true,
   185  		},
   186  		{
   187  			db:             committerDB,
   188  			batchUpdateMap: map[string]*batchableDocument{"key2": {CouchDoc: *couchDocKey2}},
   189  			namespace:      "ns",
   190  			cacheKVs:       make(statedb.CacheKVs),
   191  			cacheEnabled:   true,
   192  		},
   193  	}
   194  
   195  	err = db.executeCommitter(committers)
   196  	assert.NoError(t, err)
   197  	vv, err := db.GetState("ns", "key1")
   198  	assert.NoError(t, err)
   199  	assert.Equal(t, vv.Value, []byte("value1"))
   200  	assert.Equal(t, vv.Version, version.NewHeight(1, 1))
   201  
   202  	committers = []*committer{
   203  		{
   204  			db:             committerDB,
   205  			batchUpdateMap: map[string]*batchableDocument{},
   206  			namespace:      "ns",
   207  			cacheKVs:       make(statedb.CacheKVs),
   208  			cacheEnabled:   true,
   209  		},
   210  	}
   211  	err = db.executeCommitter(committers)
   212  	assert.EqualError(t, err, "error handling CouchDB request. Error:bad_request,  Status Code:400,  Reason:`docs` parameter must be an array.")
   213  }
   214  
   215  func TestCommitUpdates(t *testing.T) {
   216  	env := testEnv
   217  	env.init(t, &statedb.Cache{})
   218  	defer env.cleanup()
   219  
   220  	versionedDB, err := testEnv.DBProvider.GetDBHandle("test-commitupdates")
   221  	assert.NoError(t, err)
   222  	db := versionedDB.(*VersionedDB)
   223  
   224  	nsUpdates := map[string]*statedb.VersionedValue{
   225  		"key1": {
   226  			Value:    nil,
   227  			Metadata: nil,
   228  			Version:  version.NewHeight(1, 1),
   229  		},
   230  		"key2": {
   231  			Value:    []byte("value2"),
   232  			Metadata: nil,
   233  			Version:  version.NewHeight(1, 1),
   234  		},
   235  	}
   236  
   237  	committerDB, err := db.getNamespaceDBHandle("ns")
   238  	assert.NoError(t, err)
   239  	couchDoc, err := keyValToCouchDoc(&keyValue{key: "key1", revision: "", VersionedValue: nsUpdates["key1"]})
   240  	assert.NoError(t, err)
   241  
   242  	var tests = []struct {
   243  		committer   *committer
   244  		expectedErr string
   245  	}{
   246  		{
   247  			committer: &committer{
   248  				db:             committerDB,
   249  				batchUpdateMap: map[string]*batchableDocument{},
   250  				namespace:      "ns",
   251  				cacheKVs:       make(statedb.CacheKVs),
   252  				cacheEnabled:   true,
   253  			},
   254  			expectedErr: "error handling CouchDB request. Error:bad_request,  Status Code:400,  Reason:`docs` parameter must be an array.",
   255  		},
   256  		{
   257  			committer: &committer{
   258  				db:             committerDB,
   259  				batchUpdateMap: map[string]*batchableDocument{"key1": {CouchDoc: *couchDoc}},
   260  				namespace:      "ns",
   261  				cacheKVs:       make(statedb.CacheKVs),
   262  				cacheEnabled:   true,
   263  			},
   264  			expectedErr: "",
   265  		},
   266  		{
   267  			committer: &committer{
   268  				db:             committerDB,
   269  				batchUpdateMap: map[string]*batchableDocument{"key1": {CouchDoc: *couchDoc}},
   270  				namespace:      "ns",
   271  				cacheKVs:       make(statedb.CacheKVs),
   272  				cacheEnabled:   true,
   273  			},
   274  			expectedErr: "error saving document ID: key1. Error: conflict,  Reason: Document update conflict.: error handling CouchDB request. Error:conflict,  Status Code:409,  Reason:Document update conflict.",
   275  		},
   276  	}
   277  
   278  	for _, test := range tests {
   279  		err := test.committer.commitUpdates()
   280  		if test.expectedErr == "" {
   281  			assert.NoError(t, err)
   282  		} else {
   283  			assert.EqualError(t, err, test.expectedErr)
   284  		}
   285  	}
   286  
   287  	couchDoc, err = keyValToCouchDoc(&keyValue{key: "key2", revision: "", VersionedValue: nsUpdates["key2"]})
   288  	assert.NoError(t, err)
   289  
   290  	committer := &committer{
   291  		db:             committerDB,
   292  		batchUpdateMap: map[string]*batchableDocument{"key2": {CouchDoc: *couchDoc}},
   293  		namespace:      "ns",
   294  		cacheKVs:       statedb.CacheKVs{"key2": &statedb.CacheValue{}},
   295  		cacheEnabled:   true,
   296  	}
   297  
   298  	assert.Empty(t, committer.cacheKVs["key2"].AdditionalInfo)
   299  	err = committer.commitUpdates()
   300  	assert.NoError(t, err)
   301  	assert.NotEmpty(t, committer.cacheKVs["key2"].AdditionalInfo)
   302  }