github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/ledger/kvledger/txmgmt/privacyenabledstate/db_test.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package privacyenabledstate 8 9 import ( 10 "crypto/rand" 11 "encoding/hex" 12 "fmt" 13 "io" 14 "testing" 15 16 "github.com/hechain20/hechain/common/ledger/testutil" 17 "github.com/hechain20/hechain/core/common/ccprovider" 18 "github.com/hechain20/hechain/core/ledger/cceventmgmt" 19 "github.com/hechain20/hechain/core/ledger/internal/version" 20 testmock "github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/privacyenabledstate/mock" 21 "github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/statedb" 22 "github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/statedb/statecouchdb" 23 "github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/statedb/stateleveldb" 24 "github.com/hechain20/hechain/core/ledger/mock" 25 "github.com/hechain20/hechain/core/ledger/util" 26 "github.com/hyperledger/fabric-protos-go/peer" 27 "github.com/stretchr/testify/require" 28 ) 29 30 func TestHealthCheckRegister(t *testing.T) { 31 fakeHealthCheckRegistry := &mock.HealthCheckRegistry{} 32 dbProvider := &DBProvider{ 33 VersionedDBProvider: &stateleveldb.VersionedDBProvider{}, 34 HealthCheckRegistry: fakeHealthCheckRegistry, 35 } 36 37 err := dbProvider.RegisterHealthChecker() 38 require.NoError(t, err) 39 require.Equal(t, 0, fakeHealthCheckRegistry.RegisterCheckerCallCount()) 40 41 dbProvider.VersionedDBProvider = &statecouchdb.VersionedDBProvider{} 42 err = dbProvider.RegisterHealthChecker() 43 require.NoError(t, err) 44 require.Equal(t, 1, fakeHealthCheckRegistry.RegisterCheckerCallCount()) 45 46 arg1, arg2 := fakeHealthCheckRegistry.RegisterCheckerArgsForCall(0) 47 require.Equal(t, "couchdb", arg1) 48 require.NotNil(t, arg2) 49 } 50 51 func TestGetIndexInfo(t *testing.T) { 52 chaincodeIndexPath := "META-INF/statedb/couchdb/indexes" 53 actualIndexInfo := getIndexInfo(chaincodeIndexPath) 54 expectedIndexInfo := &indexInfo{ 55 hasIndexForChaincode: true, 56 hasIndexForCollection: false, 57 collectionName: "", 58 } 59 require.Equal(t, expectedIndexInfo, actualIndexInfo) 60 61 collectionIndexPath := "META-INF/statedb/couchdb/collections/collectionMarbles/indexes" 62 actualIndexInfo = getIndexInfo(collectionIndexPath) 63 expectedIndexInfo = &indexInfo{ 64 hasIndexForChaincode: false, 65 hasIndexForCollection: true, 66 collectionName: "collectionMarbles", 67 } 68 require.Equal(t, expectedIndexInfo, actualIndexInfo) 69 70 incorrectChaincodeIndexPath := "META-INF/statedb/couchdb" 71 actualIndexInfo = getIndexInfo(incorrectChaincodeIndexPath) 72 expectedIndexInfo = &indexInfo{ 73 hasIndexForChaincode: false, 74 hasIndexForCollection: false, 75 collectionName: "", 76 } 77 require.Equal(t, expectedIndexInfo, actualIndexInfo) 78 79 incorrectCollectionIndexPath := "META-INF/statedb/couchdb/collections/indexes" 80 actualIndexInfo = getIndexInfo(incorrectCollectionIndexPath) 81 require.Equal(t, expectedIndexInfo, actualIndexInfo) 82 83 incorrectCollectionIndexPath = "META-INF/statedb/couchdb/collections" 84 actualIndexInfo = getIndexInfo(incorrectCollectionIndexPath) 85 require.Equal(t, expectedIndexInfo, actualIndexInfo) 86 87 incorrectIndexPath := "META-INF/statedb" 88 actualIndexInfo = getIndexInfo(incorrectIndexPath) 89 require.Equal(t, expectedIndexInfo, actualIndexInfo) 90 } 91 92 func TestDB(t *testing.T) { 93 for _, env := range testEnvs { 94 t.Run(env.GetName(), func(t *testing.T) { 95 testDB(t, env) 96 }) 97 } 98 } 99 100 func testDB(t *testing.T, env TestEnv) { 101 env.Init(t) 102 defer env.Cleanup() 103 db := env.GetDBHandle(generateLedgerID(t)) 104 105 updates := NewUpdateBatch() 106 107 updates.PubUpdates.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 1)) 108 updates.PubUpdates.Put("ns1", "key2", []byte("value2"), version.NewHeight(1, 2)) 109 updates.PubUpdates.Put("ns2", "key3", []byte("value3"), version.NewHeight(1, 3)) 110 111 putPvtUpdates(t, updates, "ns1", "coll1", "key1", []byte("pvt_value1"), version.NewHeight(1, 4)) 112 putPvtUpdates(t, updates, "ns1", "coll1", "key2", []byte("pvt_value2"), version.NewHeight(1, 5)) 113 putPvtUpdates(t, updates, "ns2", "coll1", "key3", []byte("pvt_value3"), version.NewHeight(1, 6)) 114 require.NoError(t, db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(2, 6))) 115 bulkOptimizable, ok := db.VersionedDB.(statedb.BulkOptimizable) 116 if ok { 117 bulkOptimizable.ClearCachedVersions() 118 } 119 120 vv, err := db.GetState("ns1", "key1") 121 require.NoError(t, err) 122 require.Equal(t, &statedb.VersionedValue{Value: []byte("value1"), Version: version.NewHeight(1, 1)}, vv) 123 124 vv, err = db.GetPrivateData("ns1", "coll1", "key1") 125 require.NoError(t, err) 126 require.Equal(t, &statedb.VersionedValue{Value: []byte("pvt_value1"), Version: version.NewHeight(1, 4)}, vv) 127 128 vv, err = db.GetPrivateDataHash("ns1", "coll1", "key1") 129 require.NoError(t, err) 130 require.Equal(t, &statedb.VersionedValue{Value: util.ComputeStringHash("pvt_value1"), Version: version.NewHeight(1, 4)}, vv) 131 132 vv, err = db.GetValueHash("ns1", "coll1", util.ComputeStringHash("key1")) 133 require.NoError(t, err) 134 require.Equal(t, &statedb.VersionedValue{Value: util.ComputeStringHash("pvt_value1"), Version: version.NewHeight(1, 4)}, vv) 135 136 committedVersion, err := db.GetKeyHashVersion("ns1", "coll1", util.ComputeStringHash("key1")) 137 require.NoError(t, err) 138 require.Equal(t, version.NewHeight(1, 4), committedVersion) 139 140 updates = NewUpdateBatch() 141 updates.PubUpdates.Delete("ns1", "key1", version.NewHeight(2, 7)) 142 deletePvtUpdates(t, updates, "ns1", "coll1", "key1", version.NewHeight(2, 7)) 143 require.NoError(t, db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(2, 7))) 144 145 vv, err = db.GetState("ns1", "key1") 146 require.NoError(t, err) 147 require.Nil(t, vv) 148 149 vv, err = db.GetPrivateData("ns1", "coll1", "key1") 150 require.NoError(t, err) 151 require.Nil(t, vv) 152 153 vv, err = db.GetValueHash("ns1", "coll1", util.ComputeStringHash("key1")) 154 require.NoError(t, err) 155 require.Nil(t, vv) 156 } 157 158 func TestGetStateMultipleKeys(t *testing.T) { 159 for _, env := range testEnvs { 160 t.Run(env.GetName(), func(t *testing.T) { 161 testGetStateMultipleKeys(t, env) 162 }) 163 } 164 } 165 166 func testGetStateMultipleKeys(t *testing.T, env TestEnv) { 167 env.Init(t) 168 defer env.Cleanup() 169 db := env.GetDBHandle(generateLedgerID(t)) 170 171 updates := NewUpdateBatch() 172 173 updates.PubUpdates.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 1)) 174 updates.PubUpdates.Put("ns1", "key2", []byte("value2"), version.NewHeight(1, 2)) 175 updates.PubUpdates.Put("ns1", "key3", []byte("value3"), version.NewHeight(1, 3)) 176 177 putPvtUpdates(t, updates, "ns1", "coll1", "key1", []byte("pvt_value1"), version.NewHeight(1, 4)) 178 putPvtUpdates(t, updates, "ns1", "coll1", "key2", []byte("pvt_value2"), version.NewHeight(1, 5)) 179 putPvtUpdates(t, updates, "ns1", "coll1", "key3", []byte("pvt_value3"), version.NewHeight(1, 6)) 180 require.NoError(t, db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(2, 6))) 181 182 versionedVals, err := db.GetStateMultipleKeys("ns1", []string{"key1", "key3"}) 183 require.NoError(t, err) 184 require.Equal(t, 185 []*statedb.VersionedValue{ 186 {Value: []byte("value1"), Version: version.NewHeight(1, 1)}, 187 {Value: []byte("value3"), Version: version.NewHeight(1, 3)}, 188 }, 189 versionedVals) 190 191 pvtVersionedVals, err := db.GetPrivateDataMultipleKeys("ns1", "coll1", []string{"key1", "key3"}) 192 require.NoError(t, err) 193 require.Equal(t, 194 []*statedb.VersionedValue{ 195 {Value: []byte("pvt_value1"), Version: version.NewHeight(1, 4)}, 196 {Value: []byte("pvt_value3"), Version: version.NewHeight(1, 6)}, 197 }, 198 pvtVersionedVals) 199 } 200 201 func TestGetStateRangeScanIterator(t *testing.T) { 202 for _, env := range testEnvs { 203 t.Run(env.GetName(), func(t *testing.T) { 204 testGetStateRangeScanIterator(t, env) 205 }) 206 } 207 } 208 209 func testGetStateRangeScanIterator(t *testing.T, env TestEnv) { 210 env.Init(t) 211 defer env.Cleanup() 212 db := env.GetDBHandle(generateLedgerID(t)) 213 214 updates := NewUpdateBatch() 215 216 updates.PubUpdates.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 1)) 217 updates.PubUpdates.Put("ns1", "key2", []byte("value2"), version.NewHeight(1, 2)) 218 updates.PubUpdates.Put("ns1", "key3", []byte("value3"), version.NewHeight(1, 3)) 219 updates.PubUpdates.Put("ns1", "key4", []byte("value4"), version.NewHeight(1, 4)) 220 updates.PubUpdates.Put("ns2", "key5", []byte("value5"), version.NewHeight(1, 5)) 221 updates.PubUpdates.Put("ns2", "key6", []byte("value6"), version.NewHeight(1, 6)) 222 updates.PubUpdates.Put("ns3", "key7", []byte("value7"), version.NewHeight(1, 7)) 223 224 putPvtUpdates(t, updates, "ns1", "coll1", "key1", []byte("pvt_value1"), version.NewHeight(1, 1)) 225 putPvtUpdates(t, updates, "ns1", "coll1", "key2", []byte("pvt_value2"), version.NewHeight(1, 2)) 226 putPvtUpdates(t, updates, "ns1", "coll1", "key3", []byte("pvt_value3"), version.NewHeight(1, 3)) 227 putPvtUpdates(t, updates, "ns1", "coll1", "key4", []byte("pvt_value4"), version.NewHeight(1, 4)) 228 putPvtUpdates(t, updates, "ns2", "coll1", "key5", []byte("pvt_value5"), version.NewHeight(1, 5)) 229 putPvtUpdates(t, updates, "ns2", "coll1", "key6", []byte("pvt_value6"), version.NewHeight(1, 6)) 230 putPvtUpdates(t, updates, "ns3", "coll1", "key7", []byte("pvt_value7"), version.NewHeight(1, 7)) 231 require.NoError(t, db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(2, 7))) 232 233 itr1, _ := db.GetStateRangeScanIterator("ns1", "key1", "") 234 testItr(t, itr1, []string{"key1", "key2", "key3", "key4"}) 235 236 itr2, _ := db.GetStateRangeScanIterator("ns1", "key2", "key3") 237 testItr(t, itr2, []string{"key2"}) 238 239 itr3, _ := db.GetStateRangeScanIterator("ns1", "", "") 240 testItr(t, itr3, []string{"key1", "key2", "key3", "key4"}) 241 242 itr4, _ := db.GetStateRangeScanIterator("ns2", "", "") 243 testItr(t, itr4, []string{"key5", "key6"}) 244 245 pvtItr1, _ := db.GetPrivateDataRangeScanIterator("ns1", "coll1", "key1", "") 246 testItr(t, pvtItr1, []string{"key1", "key2", "key3", "key4"}) 247 248 pvtItr2, _ := db.GetPrivateDataRangeScanIterator("ns1", "coll1", "key2", "key3") 249 testItr(t, pvtItr2, []string{"key2"}) 250 251 pvtItr3, _ := db.GetPrivateDataRangeScanIterator("ns1", "coll1", "", "") 252 testItr(t, pvtItr3, []string{"key1", "key2", "key3", "key4"}) 253 254 pvtItr4, _ := db.GetPrivateDataRangeScanIterator("ns2", "coll1", "", "") 255 testItr(t, pvtItr4, []string{"key5", "key6"}) 256 } 257 258 func TestQueryOnCouchDB(t *testing.T) { 259 for _, env := range testEnvs { 260 _, ok := env.(*CouchDBTestEnv) 261 if !ok { 262 continue 263 } 264 t.Run(env.GetName(), func(t *testing.T) { 265 testQueryOnCouchDB(t, env) 266 }) 267 } 268 } 269 270 func testQueryOnCouchDB(t *testing.T, env TestEnv) { 271 env.Init(t) 272 defer env.Cleanup() 273 db := env.GetDBHandle(generateLedgerID(t)) 274 updates := NewUpdateBatch() 275 276 jsonValues := []string{ 277 `{"asset_name": "marble1", "color": "blue", "size": 1, "owner": "tom"}`, 278 `{"asset_name": "marble2","color": "blue","size": 2,"owner": "jerry"}`, 279 `{"asset_name": "marble3","color": "blue","size": 3,"owner": "fred"}`, 280 `{"asset_name": "marble4","color": "blue","size": 4,"owner": "martha"}`, 281 `{"asset_name": "marble5","color": "blue","size": 5,"owner": "fred"}`, 282 `{"asset_name": "marble6","color": "blue","size": 6,"owner": "elaine"}`, 283 `{"asset_name": "marble7","color": "blue","size": 7,"owner": "fred"}`, 284 `{"asset_name": "marble8","color": "blue","size": 8,"owner": "elaine"}`, 285 `{"asset_name": "marble9","color": "green","size": 9,"owner": "fred"}`, 286 `{"asset_name": "marble10","color": "green","size": 10,"owner": "mary"}`, 287 `{"asset_name": "marble11","color": "cyan","size": 1000007,"owner": "joe"}`, 288 } 289 290 for i, jsonValue := range jsonValues { 291 updates.PubUpdates.Put("ns1", testKey(i), []byte(jsonValue), version.NewHeight(1, uint64(i))) 292 updates.PubUpdates.Put("ns2", testKey(i), []byte(jsonValue), version.NewHeight(1, uint64(i))) 293 putPvtUpdates(t, updates, "ns1", "coll1", testKey(i), []byte(jsonValue), version.NewHeight(1, uint64(i))) 294 putPvtUpdates(t, updates, "ns2", "coll1", testKey(i), []byte(jsonValue), version.NewHeight(1, uint64(i))) 295 } 296 require.NoError(t, db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(1, 11))) 297 298 // query for owner=jerry, use namespace "ns1" 299 itr, err := db.ExecuteQuery("ns1", `{"selector":{"owner":"jerry"}}`) 300 require.NoError(t, err) 301 testQueryItr(t, itr, []string{testKey(1)}, []string{"jerry"}) 302 303 // query for owner=jerry, use namespace "ns2" 304 itr, err = db.ExecuteQuery("ns2", `{"selector":{"owner":"jerry"}}`) 305 require.NoError(t, err) 306 testQueryItr(t, itr, []string{testKey(1)}, []string{"jerry"}) 307 308 // query for pvt data owner=jerry, use namespace "ns1" 309 itr, err = db.ExecuteQueryOnPrivateData("ns1", "coll1", `{"selector":{"owner":"jerry"}}`) 310 require.NoError(t, err) 311 testQueryItr(t, itr, []string{testKey(1)}, []string{"jerry"}) 312 313 // query for pvt data owner=jerry, use namespace "ns2" 314 itr, err = db.ExecuteQueryOnPrivateData("ns2", "coll1", `{"selector":{"owner":"jerry"}}`) 315 require.NoError(t, err) 316 testQueryItr(t, itr, []string{testKey(1)}, []string{"jerry"}) 317 318 // query using bad query string 319 _, err = db.ExecuteQueryOnPrivateData("ns1", "coll1", "this is an invalid query string") 320 require.Error(t, err, "Should have received an error for invalid query string") 321 322 // query returns 0 records 323 itr, err = db.ExecuteQueryOnPrivateData("ns1", "coll1", `{"selector":{"owner":"not_a_valid_name"}}`) 324 require.NoError(t, err) 325 testQueryItr(t, itr, []string{}, []string{}) 326 327 // query with embedded implicit "AND" and explicit "OR", namespace "ns1" 328 itr, err = db.ExecuteQueryOnPrivateData("ns1", "coll1", `{"selector":{"color":"green","$or":[{"owner":"fred"},{"owner":"mary"}]}}`) 329 require.NoError(t, err) 330 testQueryItr(t, itr, []string{testKey(8), testKey(9)}, []string{"green"}, []string{"green"}) 331 332 // query with integer with digit-count equals 7 and response received is also received 333 // with same digit-count and there is no float transformation 334 itr, err = db.ExecuteQueryOnPrivateData("ns2", "coll1", `{"selector":{"$and":[{"size":{"$eq": 1000007}}]}}`) 335 require.NoError(t, err) 336 testQueryItr(t, itr, []string{testKey(10)}, []string{"joe", "1000007"}) 337 } 338 339 func TestLongDBNameOnCouchDB(t *testing.T) { 340 for _, env := range testEnvs { 341 _, ok := env.(*CouchDBTestEnv) 342 if !ok { 343 continue 344 } 345 t.Run(env.GetName(), func(t *testing.T) { 346 testLongDBNameOnCouchDB(t, env) 347 }) 348 } 349 } 350 351 func testLongDBNameOnCouchDB(t *testing.T, env TestEnv) { 352 env.Init(t) 353 defer env.Cleanup() 354 355 // Creates metadataDB (i.e., chainDB) 356 // Allowed pattern for chainName: [a-z][a-z0-9.-] 357 db := env.GetDBHandle("w1coaii9ck3l8red6a5cf3rwbe1b4wvbzcrrfl7samu7px8b9gf-4hft7wrgdmzzjj9ure4cbffucaj78nbj9ej.kvl3bus1iq1qir9xlhb8a1wipuksgs3g621elzy1prr658087exwrhp-y4j55o9cld242v--oeh3br1g7m8d6l8jobn.y42cgjt1.u1ik8qxnv4ohh9kr2w2zc8hqir5u4ev23s7jygrg....s7.ohp-5bcxari8nji") 358 359 updates := NewUpdateBatch() 360 361 // Allowed pattern for namespace and collection: [a-zA-Z0-9_-] 362 ns := "wMCnSXiV9YoIqNQyNvFVTdM8XnUtvrOFFIWsKelmP5NEszmNLl8YhtOKbFu3P_NgwgsYF8PsfwjYCD8f1XRpANQLoErDHwLlweryqXeJ6vzT2x0pS_GwSx0m6tBI0zOmHQOq_2De8A87x6zUOPwufC2T6dkidFxiuq8Sey2-5vUo_iNKCij3WTeCnKx78PUIg_U1gp4_0KTvYVtRBRvH0kz5usizBxPaiFu3TPhB9XLviScvdUVSbSYJ0Z" 363 coll := "vWjtfSTXVK8WJus5s6zWoMIciXd7qHRZIusF9SkOS6m8XuHCiJDE9cCRuVerq22Na8qBL2ywDGFpVMIuzfyEXLjeJb0mMuH4cwewT6r1INOTOSYwrikwOLlT_fl0V1L7IQEwUBB8WCvRqSdj6j5-E5aGul_pv_0UeCdwWiyA_GrZmP7ocLzfj2vP8btigrajqdH-irLO2ydEjQUAvf8fiuxru9la402KmKRy457GgI98UHoUdqV3f3FCdR" 364 365 updates.PubUpdates.Put(ns, "key1", []byte("value1"), version.NewHeight(1, 1)) 366 updates.PvtUpdates.Put(ns, coll, "key1", []byte("pvt_value"), version.NewHeight(1, 2)) 367 updates.HashUpdates.Put(ns, coll, util.ComputeStringHash("key1"), util.ComputeHash([]byte("pvt_value")), version.NewHeight(1, 2)) 368 369 require.NoError(t, db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(2, 6))) 370 371 vv, err := db.GetState(ns, "key1") 372 require.NoError(t, err) 373 require.Equal(t, &statedb.VersionedValue{Value: []byte("value1"), Version: version.NewHeight(1, 1)}, vv) 374 375 vv, err = db.GetPrivateData(ns, coll, "key1") 376 require.NoError(t, err) 377 require.Equal(t, &statedb.VersionedValue{Value: []byte("pvt_value"), Version: version.NewHeight(1, 2)}, vv) 378 } 379 380 func testItr(t *testing.T, itr statedb.ResultsIterator, expectedKeys []string) { 381 defer itr.Close() 382 for _, expectedKey := range expectedKeys { 383 queryResult, err := itr.Next() 384 require.NoError(t, err) 385 require.Equal(t, expectedKey, queryResult.Key) 386 } 387 last, err := itr.Next() 388 require.NoError(t, err) 389 require.Nil(t, last) 390 } 391 392 func testQueryItr(t *testing.T, itr statedb.ResultsIterator, expectedKeys []string, expectedValStrs ...[]string) { 393 defer itr.Close() 394 for i, expectedKey := range expectedKeys { 395 queryResult, err := itr.Next() 396 require.NoError(t, err) 397 valStr := string(queryResult.Value) 398 require.Equal(t, expectedKey, queryResult.Key) 399 for _, expectedValStr := range expectedValStrs[i] { 400 require.Contains(t, valStr, expectedValStr) 401 } 402 } 403 last, err := itr.Next() 404 require.NoError(t, err) 405 require.Nil(t, last) 406 } 407 408 func testKey(i int) string { 409 return fmt.Sprintf("key%d", i) 410 } 411 412 func TestHandleChainCodeDeployOnCouchDB(t *testing.T) { 413 for _, env := range testEnvs { 414 _, ok := env.(*CouchDBTestEnv) 415 if !ok { 416 continue 417 } 418 t.Run(env.GetName(), func(t *testing.T) { 419 testHandleChainCodeDeploy(t, env) 420 }) 421 } 422 } 423 424 func createCollectionConfig(collectionName string) *peer.CollectionConfig { 425 return &peer.CollectionConfig{ 426 Payload: &peer.CollectionConfig_StaticCollectionConfig{ 427 StaticCollectionConfig: &peer.StaticCollectionConfig{ 428 Name: collectionName, 429 MemberOrgsPolicy: nil, 430 RequiredPeerCount: 0, 431 MaximumPeerCount: 0, 432 BlockToLive: 0, 433 }, 434 }, 435 } 436 } 437 438 func testHandleChainCodeDeploy(t *testing.T, env TestEnv) { 439 env.Init(t) 440 defer env.Cleanup() 441 db := env.GetDBHandle(generateLedgerID(t)) 442 443 coll1 := createCollectionConfig("collectionMarbles") 444 ccp := &peer.CollectionConfigPackage{Config: []*peer.CollectionConfig{coll1}} 445 chaincodeDef := &cceventmgmt.ChaincodeDefinition{Name: "ns1", Hash: nil, Version: "", CollectionConfigs: ccp} 446 447 // Test indexes for side databases 448 dbArtifactsTarBytes := testutil.CreateTarBytesForTest( 449 []*testutil.TarFileEntry{ 450 {Name: "META-INF/statedb/couchdb/indexes/indexColorSortName.json", Body: `{"index":{"fields":[{"color":"desc"}]},"ddoc":"indexColorSortName","name":"indexColorSortName","type":"json"}`}, 451 {Name: "META-INF/statedb/couchdb/indexes/indexSizeSortName.json", Body: `{"index":{"fields":[{"size":"desc"}]},"ddoc":"indexSizeSortName","name":"indexSizeSortName","type":"json"}`}, 452 {Name: "META-INF/statedb/couchdb/collections/collectionMarbles/indexes/indexCollMarbles.json", Body: `{"index":{"fields":["docType","owner"]},"ddoc":"indexCollectionMarbles", "name":"indexCollectionMarbles","type":"json"}`}, 453 {Name: "META-INF/statedb/couchdb/collections/collectionMarblesPrivateDetails/indexes/indexCollPrivDetails.json", Body: `{"index":{"fields":["docType","price"]},"ddoc":"indexPrivateDetails", "name":"indexPrivateDetails","type":"json"}`}, 454 }, 455 ) 456 457 // Test the retrieveIndexArtifacts method 458 fileEntries, err := ccprovider.ExtractFileEntries(dbArtifactsTarBytes, "couchdb") 459 require.NoError(t, err) 460 461 // There should be 3 entries 462 require.Len(t, fileEntries, 3) 463 464 // There should be 2 entries for main 465 require.Len(t, fileEntries["META-INF/statedb/couchdb/indexes"], 2) 466 467 // There should be 1 entry for collectionMarbles 468 require.Len(t, fileEntries["META-INF/statedb/couchdb/collections/collectionMarbles/indexes"], 1) 469 470 // Verify the content of the array item 471 expectedJSON := []byte(`{"index":{"fields":["docType","owner"]},"ddoc":"indexCollectionMarbles", "name":"indexCollectionMarbles","type":"json"}`) 472 actualJSON := fileEntries["META-INF/statedb/couchdb/collections/collectionMarbles/indexes"][0].FileContent 473 require.Equal(t, expectedJSON, actualJSON) 474 475 // The collection config is added to the chaincodeDef but missing collectionMarblesPrivateDetails. 476 // Hence, the index on collectionMarblesPrivateDetails cannot be created 477 err = db.HandleChaincodeDeploy(chaincodeDef, dbArtifactsTarBytes) 478 require.NoError(t, err) 479 480 coll2 := createCollectionConfig("collectionMarblesPrivateDetails") 481 ccp = &peer.CollectionConfigPackage{Config: []*peer.CollectionConfig{coll1, coll2}} 482 chaincodeDef = &cceventmgmt.ChaincodeDefinition{Name: "ns1", Hash: nil, Version: "", CollectionConfigs: ccp} 483 484 // The collection config is added to the chaincodeDef and it contains all collections 485 // including collectionMarblesPrivateDetails which was missing earlier. 486 // Hence, the existing indexes must be updated and the new index must be created for 487 // collectionMarblesPrivateDetails 488 err = db.HandleChaincodeDeploy(chaincodeDef, dbArtifactsTarBytes) 489 require.NoError(t, err) 490 491 chaincodeDef = &cceventmgmt.ChaincodeDefinition{Name: "ns1", Hash: nil, Version: "", CollectionConfigs: nil} 492 493 // The collection config is not added to the chaincodeDef. In this case, the index creation 494 // process reads the collection config from state db. However, the state db does not contain 495 // any collection config for this chaincode. Hence, index creation/update on all collections 496 // should fail 497 err = db.HandleChaincodeDeploy(chaincodeDef, dbArtifactsTarBytes) 498 require.NoError(t, err) 499 500 // Test HandleChaincodeDefinition with a nil tar file 501 err = db.HandleChaincodeDeploy(chaincodeDef, nil) 502 require.NoError(t, err) 503 504 // Test HandleChaincodeDefinition with a bad tar file 505 err = db.HandleChaincodeDeploy(chaincodeDef, []byte(`This is a really bad tar file`)) 506 require.NoError(t, err, "Error should not have been thrown for a bad tar file") 507 508 // Test HandleChaincodeDefinition with a nil chaincodeDef 509 err = db.HandleChaincodeDeploy(nil, dbArtifactsTarBytes) 510 require.Error(t, err, "Error should have been thrown for a nil chaincodeDefinition") 511 512 // Create a tar file for test with 2 index definitions - one of them being errorneous 513 badSyntaxFileContent := `{"index":{"fields": This is a bad json}` 514 dbArtifactsTarBytes = testutil.CreateTarBytesForTest( 515 []*testutil.TarFileEntry{ 516 {Name: "META-INF/statedb/couchdb/indexes/indexSizeSortName.json", Body: `{"index":{"fields":[{"size":"desc"}]},"ddoc":"indexSizeSortName","name":"indexSizeSortName","type":"json"}`}, 517 {Name: "META-INF/statedb/couchdb/indexes/badSyntax.json", Body: badSyntaxFileContent}, 518 }, 519 ) 520 521 // Test the retrieveIndexArtifacts method 522 fileEntries, err = ccprovider.ExtractFileEntries(dbArtifactsTarBytes, "couchdb") 523 require.NoError(t, err) 524 525 // There should be 1 entry 526 require.Len(t, fileEntries, 1) 527 528 err = db.HandleChaincodeDeploy(chaincodeDef, dbArtifactsTarBytes) 529 require.NoError(t, err) 530 } 531 532 func TestMetadataRetrieval(t *testing.T) { 533 for _, env := range testEnvs { 534 t.Run(env.GetName(), func(t *testing.T) { 535 testMetadataRetrieval(t, env) 536 }) 537 } 538 } 539 540 func testMetadataRetrieval(t *testing.T, env TestEnv) { 541 env.Init(t) 542 defer env.Cleanup() 543 db := env.GetDBHandle(generateLedgerID(t)) 544 545 updates := NewUpdateBatch() 546 updates.PubUpdates.PutValAndMetadata("ns1", "key1", []byte("value1"), []byte("metadata1"), version.NewHeight(1, 1)) 547 updates.PubUpdates.PutValAndMetadata("ns1", "key2", []byte("value2"), nil, version.NewHeight(1, 2)) 548 updates.PubUpdates.PutValAndMetadata("ns2", "key3", []byte("value3"), nil, version.NewHeight(1, 3)) 549 550 putPvtUpdatesWithMetadata(t, updates, "ns1", "coll1", "key1", []byte("pvt_value1"), []byte("metadata1"), version.NewHeight(1, 4)) 551 putPvtUpdatesWithMetadata(t, updates, "ns1", "coll1", "key2", []byte("pvt_value2"), nil, version.NewHeight(1, 5)) 552 putPvtUpdatesWithMetadata(t, updates, "ns2", "coll1", "key3", []byte("pvt_value3"), nil, version.NewHeight(1, 6)) 553 require.NoError(t, db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(2, 6))) 554 555 vm, _ := db.GetStateMetadata("ns1", "key1") 556 require.Equal(t, vm, []byte("metadata1")) 557 vm, _ = db.GetStateMetadata("ns1", "key2") 558 require.Nil(t, vm) 559 vm, _ = db.GetStateMetadata("ns2", "key3") 560 require.Nil(t, vm) 561 562 vm, _ = db.GetPrivateDataMetadataByHash("ns1", "coll1", util.ComputeStringHash("key1")) 563 require.Equal(t, vm, []byte("metadata1")) 564 vm, _ = db.GetPrivateDataMetadataByHash("ns1", "coll1", util.ComputeStringHash("key2")) 565 require.Nil(t, vm) 566 vm, _ = db.GetPrivateDataMetadataByHash("ns2", "coll1", util.ComputeStringHash("key3")) 567 require.Nil(t, vm) 568 } 569 570 func putPvtUpdates(t *testing.T, updates *UpdateBatch, ns, coll, key string, value []byte, ver *version.Height) { 571 updates.PvtUpdates.Put(ns, coll, key, value, ver) 572 updates.HashUpdates.Put(ns, coll, util.ComputeStringHash(key), util.ComputeHash(value), ver) 573 } 574 575 func putPvtUpdatesWithMetadata(t *testing.T, updates *UpdateBatch, ns, coll, key string, value []byte, metadata []byte, ver *version.Height) { 576 updates.PvtUpdates.Put(ns, coll, key, value, ver) 577 updates.HashUpdates.PutValHashAndMetadata(ns, coll, util.ComputeStringHash(key), util.ComputeHash(value), metadata, ver) 578 } 579 580 func deletePvtUpdates(t *testing.T, updates *UpdateBatch, ns, coll, key string, ver *version.Height) { 581 updates.PvtUpdates.Delete(ns, coll, key, ver) 582 updates.HashUpdates.Delete(ns, coll, util.ComputeStringHash(key), ver) 583 } 584 585 func generateLedgerID(t *testing.T) string { 586 bytes := make([]byte, 8) 587 _, err := io.ReadFull(rand.Reader, bytes) 588 require.NoError(t, err) 589 return fmt.Sprintf("x%s", hex.EncodeToString(bytes)) 590 } 591 592 func TestDrop(t *testing.T) { 593 for _, env := range testEnvs { 594 t.Run(env.GetName(), func(t *testing.T) { 595 testDrop(t, env) 596 }) 597 598 t.Run("test-drop-error-propagation", func(t *testing.T) { 599 env.Init(t) 600 defer env.Cleanup() 601 ledgerid := generateLedgerID(t) 602 env.GetDBHandle(ledgerid) 603 env.GetProvider().Close() 604 require.EqualError(t, env.GetProvider().Drop(ledgerid), "internal leveldb error while obtaining db iterator: leveldb: closed") 605 }) 606 } 607 } 608 609 func testDrop(t *testing.T, env TestEnv) { 610 env.Init(t) 611 defer env.Cleanup() 612 ledgerid := generateLedgerID(t) 613 db := env.GetDBHandle(ledgerid) 614 615 updates := NewUpdateBatch() 616 updates.PubUpdates.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 1)) 617 putPvtUpdates(t, updates, "ns1", "coll1", "key1", []byte("pvt_value1"), version.NewHeight(1, 2)) 618 require.NoError(t, db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(2, 2))) 619 620 vv, err := db.GetState("ns1", "key1") 621 require.NoError(t, err) 622 require.Equal(t, &statedb.VersionedValue{Value: []byte("value1"), Version: version.NewHeight(1, 1)}, vv) 623 624 vv, err = db.GetPrivateData("ns1", "coll1", "key1") 625 require.NoError(t, err) 626 require.Equal(t, &statedb.VersionedValue{Value: []byte("pvt_value1"), Version: version.NewHeight(1, 2)}, vv) 627 628 vv, err = db.GetPrivateDataHash("ns1", "coll1", "key1") 629 require.NoError(t, err) 630 require.Equal(t, &statedb.VersionedValue{Value: util.ComputeStringHash("pvt_value1"), Version: version.NewHeight(1, 2)}, vv) 631 632 require.NoError(t, env.GetProvider().Drop(ledgerid)) 633 634 vv, err = db.GetState("ns1", "key1") 635 require.NoError(t, err) 636 require.Nil(t, vv) 637 638 vv, err = db.GetPrivateData("ns1", "coll1", "key1") 639 require.NoError(t, err) 640 require.Nil(t, vv) 641 642 vv, err = db.GetPrivateDataHash("ns1", "coll1", "key1") 643 require.NoError(t, err) 644 require.Nil(t, vv) 645 } 646 647 //go:generate counterfeiter -o mock/channelinfo_provider.go -fake-name ChannelInfoProvider . channelInfoProvider 648 649 func TestPossibleNamespaces(t *testing.T) { 650 namespacesAndCollections := map[string][]string{ 651 "cc1": {"_implicit_org_Org1MSP", "_implicit_org_Org2MSP", "collectionA", "collectionB"}, 652 "cc2": {"_implicit_org_Org1MSP", "_implicit_org_Org2MSP"}, 653 "_lifecycle": {"_implicit_org_Org1MSP", "_implicit_org_Org2MSP"}, 654 "lscc": {}, 655 "": {}, 656 } 657 expectedNamespaces := []string{ 658 "cc1", 659 "cc1$$p_implicit_org_Org1MSP", 660 "cc1$$h_implicit_org_Org1MSP", 661 "cc1$$p_implicit_org_Org2MSP", 662 "cc1$$h_implicit_org_Org2MSP", 663 "cc1$$pcollectionA", 664 "cc1$$hcollectionA", 665 "cc1$$pcollectionB", 666 "cc1$$hcollectionB", 667 "cc2", 668 "cc2$$p_implicit_org_Org1MSP", 669 "cc2$$h_implicit_org_Org1MSP", 670 "cc2$$p_implicit_org_Org2MSP", 671 "cc2$$h_implicit_org_Org2MSP", 672 "_lifecycle", 673 "_lifecycle$$p_implicit_org_Org1MSP", 674 "_lifecycle$$h_implicit_org_Org1MSP", 675 "_lifecycle$$p_implicit_org_Org2MSP", 676 "_lifecycle$$h_implicit_org_Org2MSP", 677 "lscc", 678 "", 679 } 680 681 fakeChannelInfoProvider := &testmock.ChannelInfoProvider{} 682 fakeChannelInfoProvider.NamespacesAndCollectionsReturns(namespacesAndCollections, nil) 683 nsProvider := &namespaceProvider{fakeChannelInfoProvider} 684 namespaces, err := nsProvider.PossibleNamespaces(&statecouchdb.VersionedDB{}) 685 require.NoError(t, err) 686 require.ElementsMatch(t, expectedNamespaces, namespaces) 687 }