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 }