github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/core/ledger/util/couchdb/couchdb_test.go (about) 1 /* 2 Copyright IBM Corp. 2016, 2017 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package couchdb 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "net/http" 23 "os" 24 "strings" 25 "testing" 26 "time" 27 "unicode/utf8" 28 29 "github.com/hyperledger/fabric/common/ledger/testutil" 30 "github.com/hyperledger/fabric/core/ledger/ledgerconfig" 31 ledgertestutil "github.com/hyperledger/fabric/core/ledger/testutil" 32 "github.com/spf13/viper" 33 ) 34 35 const badConnectURL = "couchdb:5990" 36 const badParseConnectURL = "http://host.com|5432" 37 const updateDocumentConflictError = "conflict" 38 const updateDocumentConflictReason = "Document update conflict." 39 40 var couchDBDef *CouchDBDef 41 42 func cleanup(database string) error { 43 //create a new connection 44 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 45 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 46 47 if err != nil { 48 fmt.Println("Unexpected error", err) 49 return err 50 } 51 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 52 //drop the test database 53 db.DropDatabase() 54 return nil 55 } 56 57 type Asset struct { 58 ID string `json:"_id"` 59 Rev string `json:"_rev"` 60 AssetName string `json:"asset_name"` 61 Color string `json:"color"` 62 Size string `json:"size"` 63 Owner string `json:"owner"` 64 } 65 66 var assetJSON = []byte(`{"asset_name":"marble1","color":"blue","size":"35","owner":"jerry"}`) 67 68 func TestMain(m *testing.M) { 69 // Read the core.yaml file for default config. 70 ledgertestutil.SetupCoreYAMLConfig() 71 72 // Switch to CouchDB 73 viper.Set("ledger.state.stateDatabase", "CouchDB") 74 75 // both vagrant and CI have couchdb configured at host "couchdb" 76 viper.Set("ledger.state.couchDBConfig.couchDBAddress", "couchdb:5984") 77 // Replace with correct username/password such as 78 // admin/admin if user security is enabled on couchdb. 79 viper.Set("ledger.state.couchDBConfig.username", "") 80 viper.Set("ledger.state.couchDBConfig.password", "") 81 viper.Set("ledger.state.couchDBConfig.maxRetries", 3) 82 viper.Set("ledger.state.couchDBConfig.maxRetriesOnStartup", 10) 83 viper.Set("ledger.state.couchDBConfig.requestTimeout", time.Second*35) 84 85 // Create CouchDB definition from config parameters 86 couchDBDef = GetCouchDBDefinition() 87 88 //run the tests 89 result := m.Run() 90 91 //revert to default goleveldb 92 viper.Set("ledger.state.stateDatabase", "goleveldb") 93 os.Exit(result) 94 } 95 96 func TestDBConnectionDef(t *testing.T) { 97 98 //create a new connection 99 _, err := CreateConnectionDefinition(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 100 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 101 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create database connection definition")) 102 103 } 104 105 func TestDBBadConnectionDef(t *testing.T) { 106 107 //create a new connection 108 _, err := CreateConnectionDefinition(badParseConnectURL, couchDBDef.Username, couchDBDef.Password, 109 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 110 testutil.AssertError(t, err, fmt.Sprintf("Did not receive error when trying to create database connection definition with a bad hostname")) 111 112 } 113 114 func TestEncodePathElement(t *testing.T) { 115 116 encodedString := encodePathElement("testelement") 117 testutil.AssertEquals(t, encodedString, "testelement") 118 119 encodedString = encodePathElement("test element") 120 testutil.AssertEquals(t, encodedString, "test%20element") 121 122 encodedString = encodePathElement("/test element") 123 testutil.AssertEquals(t, encodedString, "%2Ftest%20element") 124 125 encodedString = encodePathElement("/test element:") 126 testutil.AssertEquals(t, encodedString, "%2Ftest%20element:") 127 128 encodedString = encodePathElement("/test+ element:") 129 testutil.AssertEquals(t, encodedString, "%2Ftest%2B%20element:") 130 131 } 132 133 func TestBadCouchDBInstance(t *testing.T) { 134 135 //TODO continue changes to return and removal of sprintf in followon changes 136 if !ledgerconfig.IsCouchDBEnabled() { 137 t.Skip("CouchDB is not enabled") 138 return 139 } 140 //Create a bad connection definition 141 badConnectDef := CouchConnectionDef{URL: badParseConnectURL, Username: "", Password: "", 142 MaxRetries: 3, MaxRetriesOnStartup: 10, RequestTimeout: time.Second * 30} 143 144 client := &http.Client{} 145 146 //Create a bad couchdb instance 147 badCouchDBInstance := CouchInstance{badConnectDef, client} 148 149 //Create a bad CouchDatabase 150 badDB := CouchDatabase{badCouchDBInstance, "baddb"} 151 152 //Test CreateCouchDatabase with bad connection 153 _, err := CreateCouchDatabase(badCouchDBInstance, "baddbtest") 154 testutil.AssertError(t, err, "Error should have been thrown with CreateCouchDatabase and invalid connection") 155 156 //Test CreateSystemDatabasesIfNotExist with bad connection 157 err = CreateSystemDatabasesIfNotExist(badCouchDBInstance) 158 testutil.AssertError(t, err, "Error should have been thrown with CreateSystemDatabasesIfNotExist and invalid connection") 159 160 //Test CreateDatabaseIfNotExist with bad connection 161 _, err = badDB.CreateDatabaseIfNotExist() 162 testutil.AssertError(t, err, "Error should have been thrown with CreateDatabaseIfNotExist and invalid connection") 163 164 //Test GetDatabaseInfo with bad connection 165 _, _, err = badDB.GetDatabaseInfo() 166 testutil.AssertError(t, err, "Error should have been thrown with GetDatabaseInfo and invalid connection") 167 168 //Test VerifyCouchConfig with bad connection 169 _, _, err = badCouchDBInstance.VerifyCouchConfig() 170 testutil.AssertError(t, err, "Error should have been thrown with VerifyCouchConfig and invalid connection") 171 172 //Test EnsureFullCommit with bad connection 173 _, err = badDB.EnsureFullCommit() 174 testutil.AssertError(t, err, "Error should have been thrown with EnsureFullCommit and invalid connection") 175 176 //Test DropDatabase with bad connection 177 _, err = badDB.DropDatabase() 178 testutil.AssertError(t, err, "Error should have been thrown with DropDatabase and invalid connection") 179 180 //Test ReadDoc with bad connection 181 _, _, err = badDB.ReadDoc("1") 182 testutil.AssertError(t, err, "Error should have been thrown with ReadDoc and invalid connection") 183 184 //Test SaveDoc with bad connection 185 _, err = badDB.SaveDoc("1", "1", nil) 186 testutil.AssertError(t, err, "Error should have been thrown with SaveDoc and invalid connection") 187 188 //Test DeleteDoc with bad connection 189 err = badDB.DeleteDoc("1", "1") 190 testutil.AssertError(t, err, "Error should have been thrown with DeleteDoc and invalid connection") 191 192 //Test ReadDocRange with bad connection 193 _, err = badDB.ReadDocRange("1", "2", 1000, 0) 194 testutil.AssertError(t, err, "Error should have been thrown with ReadDocRange and invalid connection") 195 196 //Test QueryDocuments with bad connection 197 _, err = badDB.QueryDocuments("1") 198 testutil.AssertError(t, err, "Error should have been thrown with QueryDocuments and invalid connection") 199 200 //Test BatchRetrieveIDRevision with bad connection 201 _, err = badDB.BatchRetrieveIDRevision(nil) 202 testutil.AssertError(t, err, "Error should have been thrown with BatchRetrieveIDRevision and invalid connection") 203 204 //Test BatchUpdateDocuments with bad connection 205 _, err = badDB.BatchUpdateDocuments(nil) 206 testutil.AssertError(t, err, "Error should have been thrown with BatchUpdateDocuments and invalid connection") 207 208 } 209 210 func TestDBCreateSaveWithoutRevision(t *testing.T) { 211 212 if ledgerconfig.IsCouchDBEnabled() { 213 214 database := "testdbcreatesavewithoutrevision" 215 err := cleanup(database) 216 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 217 defer cleanup(database) 218 219 if err == nil { 220 //create a new instance and database object 221 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 222 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 223 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 224 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 225 226 //create a new database 227 _, errdb := db.CreateDatabaseIfNotExist() 228 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database")) 229 230 //Save the test document 231 _, saveerr := db.SaveDoc("2", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 232 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 233 } 234 } 235 } 236 237 func TestDBCreateEnsureFullCommit(t *testing.T) { 238 239 if ledgerconfig.IsCouchDBEnabled() { 240 241 database := "testdbensurefullcommit" 242 err := cleanup(database) 243 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 244 defer cleanup(database) 245 246 if err == nil { 247 //create a new instance and database object 248 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 249 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 250 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 251 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 252 253 //create a new database 254 _, errdb := db.CreateDatabaseIfNotExist() 255 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database")) 256 257 //Save the test document 258 _, saveerr := db.SaveDoc("2", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 259 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 260 261 //Ensure a full commit 262 _, commiterr := db.EnsureFullCommit() 263 testutil.AssertNoError(t, commiterr, fmt.Sprintf("Error when trying to ensure a full commit")) 264 265 } 266 } 267 } 268 269 func TestDBBadDatabaseName(t *testing.T) { 270 271 if ledgerconfig.IsCouchDBEnabled() { 272 273 //create a new instance and database object using a valid database name mixed case 274 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 275 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 276 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 277 _, dberr := CreateCouchDatabase(*couchInstance, "testDB") 278 testutil.AssertError(t, dberr, "Error should have been thrown for an invalid db name") 279 280 //create a new instance and database object using a valid database name letters and numbers 281 couchInstance, err = CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 282 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 283 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 284 _, dberr = CreateCouchDatabase(*couchInstance, "test132") 285 testutil.AssertNoError(t, dberr, fmt.Sprintf("Error when testing a valid database name")) 286 287 //create a new instance and database object using a valid database name - special characters 288 couchInstance, err = CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 289 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 290 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 291 _, dberr = CreateCouchDatabase(*couchInstance, "test1234~!@#$%^&*()[]{}.") 292 testutil.AssertError(t, dberr, "Error should have been thrown for an invalid db name") 293 294 //create a new instance and database object using a invalid database name - too long /* 295 couchInstance, err = CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 296 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 297 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 298 _, dberr = CreateCouchDatabase(*couchInstance, "a12345678901234567890123456789012345678901234"+ 299 "56789012345678901234567890123456789012345678901234567890123456789012345678901234567890"+ 300 "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456"+ 301 "78901234567890123456789012345678901234567890") 302 testutil.AssertError(t, dberr, fmt.Sprintf("Error should have been thrown for invalid database name")) 303 304 } 305 } 306 307 func TestDBBadConnection(t *testing.T) { 308 309 if ledgerconfig.IsCouchDBEnabled() { 310 311 //create a new instance and database object 312 //Limit the maxRetriesOnStartup to 3 in order to reduce time for the failure 313 _, err := CreateCouchInstance(badConnectURL, couchDBDef.Username, couchDBDef.Password, 314 couchDBDef.MaxRetries, 3, couchDBDef.RequestTimeout) 315 testutil.AssertError(t, err, fmt.Sprintf("Error should have been thrown for a bad connection")) 316 } 317 } 318 319 func TestDBCreateDatabaseAndPersist(t *testing.T) { 320 321 if ledgerconfig.IsCouchDBEnabled() { 322 323 database := "testdbcreatedatabaseandpersist" 324 err := cleanup(database) 325 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 326 defer cleanup(database) 327 328 if err == nil { 329 //create a new instance and database object 330 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 331 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 332 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 333 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 334 335 //create a new database 336 _, errdb := db.CreateDatabaseIfNotExist() 337 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database")) 338 339 //Retrieve the info for the new database and make sure the name matches 340 dbResp, _, errdb := db.GetDatabaseInfo() 341 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to retrieve database information")) 342 testutil.AssertEquals(t, dbResp.DbName, database) 343 344 //Save the test document 345 _, saveerr := db.SaveDoc("idWith/slash", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 346 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 347 348 //Retrieve the test document 349 dbGetResp, _, geterr := db.ReadDoc("idWith/slash") 350 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document")) 351 352 //Unmarshal the document to Asset structure 353 assetResp := &Asset{} 354 geterr = json.Unmarshal(dbGetResp.JSONValue, &assetResp) 355 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document")) 356 357 //Verify the owner retrieved matches 358 testutil.AssertEquals(t, assetResp.Owner, "jerry") 359 360 //Save the test document 361 _, saveerr = db.SaveDoc("1", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 362 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 363 364 //Retrieve the test document 365 dbGetResp, _, geterr = db.ReadDoc("1") 366 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document")) 367 368 //Unmarshal the document to Asset structure 369 assetResp = &Asset{} 370 geterr = json.Unmarshal(dbGetResp.JSONValue, &assetResp) 371 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document")) 372 373 //Verify the owner retrieved matches 374 testutil.AssertEquals(t, assetResp.Owner, "jerry") 375 376 //Change owner to bob 377 assetResp.Owner = "bob" 378 379 //create a byte array of the JSON 380 assetDocUpdated, _ := json.Marshal(assetResp) 381 382 //Save the updated test document 383 _, saveerr = db.SaveDoc("1", "", &CouchDoc{JSONValue: assetDocUpdated, Attachments: nil}) 384 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save the updated document")) 385 386 //Retrieve the updated test document 387 dbGetResp, _, geterr = db.ReadDoc("1") 388 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document")) 389 390 //Unmarshal the document to Asset structure 391 assetResp = &Asset{} 392 json.Unmarshal(dbGetResp.JSONValue, &assetResp) 393 394 //Assert that the update was saved and retrieved 395 testutil.AssertEquals(t, assetResp.Owner, "bob") 396 397 testBytes2 := []byte(`test attachment 2`) 398 399 attachment2 := &Attachment{} 400 attachment2.AttachmentBytes = testBytes2 401 attachment2.ContentType = "application/octet-stream" 402 attachment2.Name = "data" 403 attachments2 := []*Attachment{} 404 attachments2 = append(attachments2, attachment2) 405 406 //Save the test document with an attachment 407 _, saveerr = db.SaveDoc("2", "", &CouchDoc{JSONValue: nil, Attachments: attachments2}) 408 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 409 410 //Retrieve the test document with attachments 411 dbGetResp, _, geterr = db.ReadDoc("2") 412 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document")) 413 414 //verify the text from the attachment is correct 415 testattach := dbGetResp.Attachments[0].AttachmentBytes 416 testutil.AssertEquals(t, testattach, testBytes2) 417 418 testBytes3 := []byte{} 419 420 attachment3 := &Attachment{} 421 attachment3.AttachmentBytes = testBytes3 422 attachment3.ContentType = "application/octet-stream" 423 attachment3.Name = "data" 424 attachments3 := []*Attachment{} 425 attachments3 = append(attachments3, attachment3) 426 427 //Save the test document with a zero length attachment 428 _, saveerr = db.SaveDoc("3", "", &CouchDoc{JSONValue: nil, Attachments: attachments3}) 429 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 430 431 //Retrieve the test document with attachments 432 dbGetResp, _, geterr = db.ReadDoc("3") 433 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document")) 434 435 //verify the text from the attachment is correct, zero bytes 436 testattach = dbGetResp.Attachments[0].AttachmentBytes 437 testutil.AssertEquals(t, testattach, testBytes3) 438 439 testBytes4a := []byte(`test attachment 4a`) 440 attachment4a := &Attachment{} 441 attachment4a.AttachmentBytes = testBytes4a 442 attachment4a.ContentType = "application/octet-stream" 443 attachment4a.Name = "data1" 444 445 testBytes4b := []byte(`test attachment 4b`) 446 attachment4b := &Attachment{} 447 attachment4b.AttachmentBytes = testBytes4b 448 attachment4b.ContentType = "application/octet-stream" 449 attachment4b.Name = "data2" 450 451 attachments4 := []*Attachment{} 452 attachments4 = append(attachments4, attachment4a) 453 attachments4 = append(attachments4, attachment4b) 454 455 //Save the updated test document with multiple attachments 456 _, saveerr = db.SaveDoc("4", "", &CouchDoc{JSONValue: assetJSON, Attachments: attachments4}) 457 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save the updated document")) 458 459 //Retrieve the test document with attachments 460 dbGetResp, _, geterr = db.ReadDoc("4") 461 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document")) 462 463 for _, attach4 := range dbGetResp.Attachments { 464 465 currentName := attach4.Name 466 if currentName == "data1" { 467 testutil.AssertEquals(t, attach4.AttachmentBytes, testBytes4a) 468 } 469 if currentName == "data2" { 470 testutil.AssertEquals(t, attach4.AttachmentBytes, testBytes4b) 471 } 472 473 } 474 475 testBytes5a := []byte(`test attachment 5a`) 476 attachment5a := &Attachment{} 477 attachment5a.AttachmentBytes = testBytes5a 478 attachment5a.ContentType = "application/octet-stream" 479 attachment5a.Name = "data1" 480 481 testBytes5b := []byte{} 482 attachment5b := &Attachment{} 483 attachment5b.AttachmentBytes = testBytes5b 484 attachment5b.ContentType = "application/octet-stream" 485 attachment5b.Name = "data2" 486 487 attachments5 := []*Attachment{} 488 attachments5 = append(attachments5, attachment5a) 489 attachments5 = append(attachments5, attachment5b) 490 491 //Save the updated test document with multiple attachments and zero length attachments 492 _, saveerr = db.SaveDoc("5", "", &CouchDoc{JSONValue: assetJSON, Attachments: attachments5}) 493 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save the updated document")) 494 495 //Retrieve the test document with attachments 496 dbGetResp, _, geterr = db.ReadDoc("5") 497 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document")) 498 499 for _, attach5 := range dbGetResp.Attachments { 500 501 currentName := attach5.Name 502 if currentName == "data1" { 503 testutil.AssertEquals(t, attach5.AttachmentBytes, testBytes5a) 504 } 505 if currentName == "data2" { 506 testutil.AssertEquals(t, attach5.AttachmentBytes, testBytes5b) 507 } 508 509 } 510 511 //Attempt to save the document with an invalid id 512 _, saveerr = db.SaveDoc(string([]byte{0xff, 0xfe, 0xfd}), "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 513 testutil.AssertError(t, saveerr, fmt.Sprintf("Error should have been thrown when saving a document with an invalid ID")) 514 515 //Attempt to read a document with an invalid id 516 _, _, readerr := db.ReadDoc(string([]byte{0xff, 0xfe, 0xfd})) 517 testutil.AssertError(t, readerr, fmt.Sprintf("Error should have been thrown when reading a document with an invalid ID")) 518 519 //Drop the database 520 _, errdbdrop := db.DropDatabase() 521 testutil.AssertNoError(t, errdbdrop, fmt.Sprintf("Error dropping database")) 522 523 //Make sure an error is thrown for getting info for a missing database 524 _, _, errdbinfo := db.GetDatabaseInfo() 525 testutil.AssertError(t, errdbinfo, fmt.Sprintf("Error should have been thrown for missing database")) 526 527 //Attempt to save a document to a deleted database 528 _, saveerr = db.SaveDoc("6", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 529 testutil.AssertError(t, saveerr, fmt.Sprintf("Error should have been thrown while attempting to save to a deleted database")) 530 531 //Attempt to read from a deleted database 532 _, _, geterr = db.ReadDoc("6") 533 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error should not have been thrown for a missing database, nil value is returned")) 534 535 } 536 } 537 538 } 539 540 func TestDBRequestTimeout(t *testing.T) { 541 542 if ledgerconfig.IsCouchDBEnabled() { 543 544 database := "testdbrequesttimeout" 545 err := cleanup(database) 546 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 547 defer cleanup(database) 548 549 if err == nil { 550 551 //create an impossibly short timeout 552 impossibleTimeout := time.Microsecond * 1 553 554 //create a new instance and database object with a timeout that will fail 555 //Also use a maxRetriesOnStartup=3 to reduce the number of retries 556 _, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 557 couchDBDef.MaxRetries, 3, impossibleTimeout) 558 testutil.AssertError(t, err, fmt.Sprintf("Error should have been thown while trying to create a couchdb instance with a connection timeout")) 559 560 //see if the error message contains the timeout error 561 testutil.AssertEquals(t, strings.Count(err.Error(), "Client.Timeout exceeded while awaiting headers"), 1) 562 563 } 564 } 565 } 566 567 func TestDBTimeoutConflictRetry(t *testing.T) { 568 569 if ledgerconfig.IsCouchDBEnabled() { 570 571 database := "testdbtimeoutretry" 572 err := cleanup(database) 573 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 574 defer cleanup(database) 575 576 // if there was an error upon cleanup, return here 577 if err != nil { 578 return 579 } 580 581 //create a new instance and database object 582 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 583 couchDBDef.MaxRetries, 3, couchDBDef.RequestTimeout) 584 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 585 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 586 587 //create a new database 588 _, errdb := db.CreateDatabaseIfNotExist() 589 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database")) 590 591 //Retrieve the info for the new database and make sure the name matches 592 dbResp, _, errdb := db.GetDatabaseInfo() 593 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to retrieve database information")) 594 testutil.AssertEquals(t, dbResp.DbName, database) 595 596 //Save the test document 597 _, saveerr := db.SaveDoc("1", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 598 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 599 600 //Retrieve the test document 601 _, _, geterr := db.ReadDoc("1") 602 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document")) 603 604 //Save the test document with an invalid rev. This should cause a retry 605 _, saveerr = db.SaveDoc("1", "1-11111111111111111111111111111111", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 606 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document with a revision conflict")) 607 608 //Delete the test document with an invalid rev. This should cause a retry 609 deleteerr := db.DeleteDoc("1", "1-11111111111111111111111111111111") 610 testutil.AssertNoError(t, deleteerr, fmt.Sprintf("Error when trying to delete a document with a revision conflict")) 611 612 } 613 } 614 615 func TestDBBadNumberOfRetries(t *testing.T) { 616 617 if ledgerconfig.IsCouchDBEnabled() { 618 619 database := "testdbbadretries" 620 err := cleanup(database) 621 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 622 defer cleanup(database) 623 624 // if there was an error upon cleanup, return here 625 if err != nil { 626 return 627 } 628 629 //create a new instance and database object 630 _, err = CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 631 0, 3, couchDBDef.RequestTimeout) 632 testutil.AssertError(t, err, fmt.Sprintf("Error should have been thrown while attempting to create a database")) 633 634 } 635 } 636 637 func TestDBBadJSON(t *testing.T) { 638 639 if ledgerconfig.IsCouchDBEnabled() { 640 641 database := "testdbbadjson" 642 err := cleanup(database) 643 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 644 defer cleanup(database) 645 646 if err == nil { 647 648 //create a new instance and database object 649 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 650 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 651 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 652 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 653 654 //create a new database 655 _, errdb := db.CreateDatabaseIfNotExist() 656 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database")) 657 658 //Retrieve the info for the new database and make sure the name matches 659 dbResp, _, errdb := db.GetDatabaseInfo() 660 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to retrieve database information")) 661 testutil.AssertEquals(t, dbResp.DbName, database) 662 663 badJSON := []byte(`{"asset_name"}`) 664 665 //Save the test document 666 _, saveerr := db.SaveDoc("1", "", &CouchDoc{JSONValue: badJSON, Attachments: nil}) 667 testutil.AssertError(t, saveerr, fmt.Sprintf("Error should have been thrown for a bad JSON")) 668 669 } 670 671 } 672 673 } 674 675 func TestPrefixScan(t *testing.T) { 676 if !ledgerconfig.IsCouchDBEnabled() { 677 return 678 } 679 database := "testprefixscan" 680 err := cleanup(database) 681 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 682 defer cleanup(database) 683 684 if err == nil { 685 //create a new instance and database object 686 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 687 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 688 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 689 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 690 691 //create a new database 692 _, errdb := db.CreateDatabaseIfNotExist() 693 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database")) 694 695 //Retrieve the info for the new database and make sure the name matches 696 dbResp, _, errdb := db.GetDatabaseInfo() 697 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to retrieve database information")) 698 testutil.AssertEquals(t, dbResp.DbName, database) 699 700 //Save documents 701 for i := 0; i < 20; i++ { 702 id1 := string(0) + string(i) + string(0) 703 id2 := string(0) + string(i) + string(1) 704 id3 := string(0) + string(i) + string(utf8.MaxRune-1) 705 _, saveerr := db.SaveDoc(id1, "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 706 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 707 _, saveerr = db.SaveDoc(id2, "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 708 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 709 _, saveerr = db.SaveDoc(id3, "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 710 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 711 712 } 713 startKey := string(0) + string(10) 714 endKey := startKey + string(utf8.MaxRune) 715 _, _, geterr := db.ReadDoc(endKey) 716 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to get lastkey")) 717 718 resultsPtr, geterr := db.ReadDocRange(startKey, endKey, 1000, 0) 719 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to perform a range scan")) 720 testutil.AssertNotNil(t, resultsPtr) 721 results := *resultsPtr 722 testutil.AssertEquals(t, len(results), 3) 723 testutil.AssertEquals(t, results[0].ID, string(0)+string(10)+string(0)) 724 testutil.AssertEquals(t, results[1].ID, string(0)+string(10)+string(1)) 725 testutil.AssertEquals(t, results[2].ID, string(0)+string(10)+string(utf8.MaxRune-1)) 726 727 //Drop the database 728 _, errdbdrop := db.DropDatabase() 729 testutil.AssertNoError(t, errdbdrop, fmt.Sprintf("Error dropping database")) 730 731 //Retrieve the info for the new database and make sure the name matches 732 _, _, errdbinfo := db.GetDatabaseInfo() 733 testutil.AssertError(t, errdbinfo, fmt.Sprintf("Error should have been thrown for missing database")) 734 735 } 736 } 737 738 func TestDBSaveAttachment(t *testing.T) { 739 740 if ledgerconfig.IsCouchDBEnabled() { 741 742 database := "testdbsaveattachment" 743 err := cleanup(database) 744 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 745 defer cleanup(database) 746 747 if err == nil { 748 749 byteText := []byte(`This is a test document. This is only a test`) 750 751 attachment := &Attachment{} 752 attachment.AttachmentBytes = byteText 753 attachment.ContentType = "text/plain" 754 attachment.Name = "valueBytes" 755 756 attachments := []*Attachment{} 757 attachments = append(attachments, attachment) 758 759 //create a new instance and database object 760 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 761 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 762 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 763 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 764 765 //create a new database 766 _, errdb := db.CreateDatabaseIfNotExist() 767 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database")) 768 769 //Save the test document 770 _, saveerr := db.SaveDoc("10", "", &CouchDoc{JSONValue: nil, Attachments: attachments}) 771 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 772 773 //Attempt to retrieve the updated test document with attachments 774 couchDoc, _, geterr2 := db.ReadDoc("10") 775 testutil.AssertNoError(t, geterr2, fmt.Sprintf("Error when trying to retrieve a document with attachment")) 776 testutil.AssertNotNil(t, couchDoc.Attachments) 777 testutil.AssertEquals(t, couchDoc.Attachments[0].AttachmentBytes, byteText) 778 } 779 780 } 781 } 782 783 func TestDBDeleteDocument(t *testing.T) { 784 785 if ledgerconfig.IsCouchDBEnabled() { 786 787 database := "testdbdeletedocument" 788 err := cleanup(database) 789 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 790 defer cleanup(database) 791 792 if err == nil { 793 //create a new instance and database object 794 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 795 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 796 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 797 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 798 799 //create a new database 800 _, errdb := db.CreateDatabaseIfNotExist() 801 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database")) 802 803 //Save the test document 804 _, saveerr := db.SaveDoc("2", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 805 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 806 807 //Attempt to retrieve the test document 808 _, _, readErr := db.ReadDoc("2") 809 testutil.AssertNoError(t, readErr, fmt.Sprintf("Error when trying to retrieve a document with attachment")) 810 811 //Delete the test document 812 deleteErr := db.DeleteDoc("2", "") 813 testutil.AssertNoError(t, deleteErr, fmt.Sprintf("Error when trying to delete a document")) 814 815 //Attempt to retrieve the test document 816 readValue, _, _ := db.ReadDoc("2") 817 testutil.AssertNil(t, readValue) 818 } 819 } 820 } 821 822 func TestDBDeleteNonExistingDocument(t *testing.T) { 823 824 if ledgerconfig.IsCouchDBEnabled() { 825 826 database := "testdbdeletenonexistingdocument" 827 err := cleanup(database) 828 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 829 defer cleanup(database) 830 831 if err == nil { 832 //create a new instance and database object 833 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 834 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 835 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 836 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 837 838 //create a new database 839 _, errdb := db.CreateDatabaseIfNotExist() 840 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database")) 841 842 //Save the test document 843 deleteErr := db.DeleteDoc("2", "") 844 testutil.AssertNoError(t, deleteErr, fmt.Sprintf("Error when trying to delete a non existing document")) 845 } 846 } 847 } 848 849 func TestCouchDBVersion(t *testing.T) { 850 851 err := checkCouchDBVersion("2.0.0") 852 testutil.AssertNoError(t, err, fmt.Sprintf("Error should not have been thrown for valid version")) 853 854 err = checkCouchDBVersion("4.5.0") 855 testutil.AssertNoError(t, err, fmt.Sprintf("Error should not have been thrown for valid version")) 856 857 err = checkCouchDBVersion("1.6.5.4") 858 testutil.AssertError(t, err, fmt.Sprintf("Error should have been thrown for invalid version")) 859 860 err = checkCouchDBVersion("0.0.0.0") 861 testutil.AssertError(t, err, fmt.Sprintf("Error should have been thrown for invalid version")) 862 863 } 864 865 func TestRichQuery(t *testing.T) { 866 867 if ledgerconfig.IsCouchDBEnabled() { 868 869 byteJSON01 := []byte(`{"asset_name":"marble01","color":"blue","size":1,"owner":"jerry"}`) 870 byteJSON02 := []byte(`{"asset_name":"marble02","color":"red","size":2,"owner":"tom"}`) 871 byteJSON03 := []byte(`{"asset_name":"marble03","color":"green","size":3,"owner":"jerry"}`) 872 byteJSON04 := []byte(`{"asset_name":"marble04","color":"purple","size":4,"owner":"tom"}`) 873 byteJSON05 := []byte(`{"asset_name":"marble05","color":"blue","size":5,"owner":"jerry"}`) 874 byteJSON06 := []byte(`{"asset_name":"marble06","color":"white","size":6,"owner":"tom"}`) 875 byteJSON07 := []byte(`{"asset_name":"marble07","color":"white","size":7,"owner":"tom"}`) 876 byteJSON08 := []byte(`{"asset_name":"marble08","color":"white","size":8,"owner":"tom"}`) 877 byteJSON09 := []byte(`{"asset_name":"marble09","color":"white","size":9,"owner":"tom"}`) 878 byteJSON10 := []byte(`{"asset_name":"marble10","color":"white","size":10,"owner":"tom"}`) 879 byteJSON11 := []byte(`{"asset_name":"marble11","color":"green","size":11,"owner":"tom"}`) 880 byteJSON12 := []byte(`{"asset_name":"marble12","color":"green","size":12,"owner":"frank"}`) 881 882 attachment1 := &Attachment{} 883 attachment1.AttachmentBytes = []byte(`marble01 - test attachment`) 884 attachment1.ContentType = "application/octet-stream" 885 attachment1.Name = "data" 886 attachments1 := []*Attachment{} 887 attachments1 = append(attachments1, attachment1) 888 889 attachment2 := &Attachment{} 890 attachment2.AttachmentBytes = []byte(`marble02 - test attachment`) 891 attachment2.ContentType = "application/octet-stream" 892 attachment2.Name = "data" 893 attachments2 := []*Attachment{} 894 attachments2 = append(attachments2, attachment2) 895 896 attachment3 := &Attachment{} 897 attachment3.AttachmentBytes = []byte(`marble03 - test attachment`) 898 attachment3.ContentType = "application/octet-stream" 899 attachment3.Name = "data" 900 attachments3 := []*Attachment{} 901 attachments3 = append(attachments3, attachment3) 902 903 attachment4 := &Attachment{} 904 attachment4.AttachmentBytes = []byte(`marble04 - test attachment`) 905 attachment4.ContentType = "application/octet-stream" 906 attachment4.Name = "data" 907 attachments4 := []*Attachment{} 908 attachments4 = append(attachments4, attachment4) 909 910 attachment5 := &Attachment{} 911 attachment5.AttachmentBytes = []byte(`marble05 - test attachment`) 912 attachment5.ContentType = "application/octet-stream" 913 attachment5.Name = "data" 914 attachments5 := []*Attachment{} 915 attachments5 = append(attachments5, attachment5) 916 917 attachment6 := &Attachment{} 918 attachment6.AttachmentBytes = []byte(`marble06 - test attachment`) 919 attachment6.ContentType = "application/octet-stream" 920 attachment6.Name = "data" 921 attachments6 := []*Attachment{} 922 attachments6 = append(attachments6, attachment6) 923 924 attachment7 := &Attachment{} 925 attachment7.AttachmentBytes = []byte(`marble07 - test attachment`) 926 attachment7.ContentType = "application/octet-stream" 927 attachment7.Name = "data" 928 attachments7 := []*Attachment{} 929 attachments7 = append(attachments7, attachment7) 930 931 attachment8 := &Attachment{} 932 attachment8.AttachmentBytes = []byte(`marble08 - test attachment`) 933 attachment8.ContentType = "application/octet-stream" 934 attachment7.Name = "data" 935 attachments8 := []*Attachment{} 936 attachments8 = append(attachments8, attachment8) 937 938 attachment9 := &Attachment{} 939 attachment9.AttachmentBytes = []byte(`marble09 - test attachment`) 940 attachment9.ContentType = "application/octet-stream" 941 attachment9.Name = "data" 942 attachments9 := []*Attachment{} 943 attachments9 = append(attachments9, attachment9) 944 945 attachment10 := &Attachment{} 946 attachment10.AttachmentBytes = []byte(`marble10 - test attachment`) 947 attachment10.ContentType = "application/octet-stream" 948 attachment10.Name = "data" 949 attachments10 := []*Attachment{} 950 attachments10 = append(attachments10, attachment10) 951 952 attachment11 := &Attachment{} 953 attachment11.AttachmentBytes = []byte(`marble11 - test attachment`) 954 attachment11.ContentType = "application/octet-stream" 955 attachment11.Name = "data" 956 attachments11 := []*Attachment{} 957 attachments11 = append(attachments11, attachment11) 958 959 attachment12 := &Attachment{} 960 attachment12.AttachmentBytes = []byte(`marble12 - test attachment`) 961 attachment12.ContentType = "application/octet-stream" 962 attachment12.Name = "data" 963 attachments12 := []*Attachment{} 964 attachments12 = append(attachments12, attachment12) 965 966 database := "testrichquery" 967 err := cleanup(database) 968 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 969 defer cleanup(database) 970 971 if err == nil { 972 //create a new instance and database object -------------------------------------------------------- 973 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 974 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 975 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 976 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 977 978 //create a new database 979 _, errdb := db.CreateDatabaseIfNotExist() 980 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database")) 981 982 //Save the test document 983 _, saveerr := db.SaveDoc("marble01", "", &CouchDoc{JSONValue: byteJSON01, Attachments: attachments1}) 984 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 985 986 //Save the test document 987 _, saveerr = db.SaveDoc("marble02", "", &CouchDoc{JSONValue: byteJSON02, Attachments: attachments2}) 988 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 989 990 //Save the test document 991 _, saveerr = db.SaveDoc("marble03", "", &CouchDoc{JSONValue: byteJSON03, Attachments: attachments3}) 992 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 993 994 //Save the test document 995 _, saveerr = db.SaveDoc("marble04", "", &CouchDoc{JSONValue: byteJSON04, Attachments: attachments4}) 996 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 997 998 //Save the test document 999 _, saveerr = db.SaveDoc("marble05", "", &CouchDoc{JSONValue: byteJSON05, Attachments: attachments5}) 1000 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 1001 1002 //Save the test document 1003 _, saveerr = db.SaveDoc("marble06", "", &CouchDoc{JSONValue: byteJSON06, Attachments: attachments6}) 1004 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 1005 1006 //Save the test document 1007 _, saveerr = db.SaveDoc("marble07", "", &CouchDoc{JSONValue: byteJSON07, Attachments: attachments7}) 1008 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 1009 1010 //Save the test document 1011 _, saveerr = db.SaveDoc("marble08", "", &CouchDoc{JSONValue: byteJSON08, Attachments: attachments8}) 1012 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 1013 1014 //Save the test document 1015 _, saveerr = db.SaveDoc("marble09", "", &CouchDoc{JSONValue: byteJSON09, Attachments: attachments9}) 1016 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 1017 1018 //Save the test document 1019 _, saveerr = db.SaveDoc("marble10", "", &CouchDoc{JSONValue: byteJSON10, Attachments: attachments10}) 1020 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 1021 1022 //Save the test document 1023 _, saveerr = db.SaveDoc("marble11", "", &CouchDoc{JSONValue: byteJSON11, Attachments: attachments11}) 1024 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 1025 1026 //Save the test document 1027 _, saveerr = db.SaveDoc("marble12", "", &CouchDoc{JSONValue: byteJSON12, Attachments: attachments12}) 1028 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 1029 1030 //Test query with invalid JSON ------------------------------------------------------------------- 1031 queryString := "{\"selector\":{\"owner\":}}" 1032 1033 _, err = db.QueryDocuments(queryString) 1034 testutil.AssertError(t, err, fmt.Sprintf("Error should have been thrown for bad json")) 1035 1036 //Test query with object ------------------------------------------------------------------- 1037 queryString = "{\"selector\":{\"owner\":{\"$eq\":\"jerry\"}}}" 1038 1039 queryResult, err := db.QueryDocuments(queryString) 1040 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to execute a query")) 1041 1042 //There should be 3 results for owner="jerry" 1043 testutil.AssertEquals(t, len(*queryResult), 3) 1044 1045 //Test query with implicit operator -------------------------------------------------------------- 1046 queryString = "{\"selector\":{\"owner\":\"jerry\"}}" 1047 1048 queryResult, err = db.QueryDocuments(queryString) 1049 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to execute a query")) 1050 1051 //There should be 3 results for owner="jerry" 1052 testutil.AssertEquals(t, len(*queryResult), 3) 1053 1054 //Test query with specified fields ------------------------------------------------------------------- 1055 queryString = "{\"selector\":{\"owner\":{\"$eq\":\"jerry\"}},\"fields\": [\"owner\",\"asset_name\",\"color\",\"size\"]}" 1056 1057 queryResult, err = db.QueryDocuments(queryString) 1058 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to execute a query")) 1059 1060 //There should be 3 results for owner="jerry" 1061 testutil.AssertEquals(t, len(*queryResult), 3) 1062 1063 //Test query with a leading operator ------------------------------------------------------------------- 1064 queryString = "{\"selector\":{\"$or\":[{\"owner\":{\"$eq\":\"jerry\"}},{\"owner\": {\"$eq\": \"frank\"}}]}}" 1065 1066 queryResult, err = db.QueryDocuments(queryString) 1067 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to execute a query")) 1068 1069 //There should be 4 results for owner="jerry" or owner="frank" 1070 testutil.AssertEquals(t, len(*queryResult), 4) 1071 1072 //Test query implicit and explicit operator ------------------------------------------------------------------ 1073 queryString = "{\"selector\":{\"color\":\"green\",\"$or\":[{\"owner\":\"tom\"},{\"owner\":\"frank\"}]}}" 1074 1075 queryResult, err = db.QueryDocuments(queryString) 1076 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to execute a query")) 1077 1078 //There should be 2 results for color="green" and (owner="jerry" or owner="frank") 1079 testutil.AssertEquals(t, len(*queryResult), 2) 1080 1081 //Test query with a leading operator ------------------------------------------------------------------------- 1082 queryString = "{\"selector\":{\"$and\":[{\"size\":{\"$gte\":2}},{\"size\":{\"$lte\":5}}]}}" 1083 1084 queryResult, err = db.QueryDocuments(queryString) 1085 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to execute a query")) 1086 1087 //There should be 4 results for size >= 2 and size <= 5 1088 testutil.AssertEquals(t, len(*queryResult), 4) 1089 1090 //Test query with leading and embedded operator ------------------------------------------------------------- 1091 queryString = "{\"selector\":{\"$and\":[{\"size\":{\"$gte\":3}},{\"size\":{\"$lte\":10}},{\"$not\":{\"size\":7}}]}}" 1092 1093 queryResult, err = db.QueryDocuments(queryString) 1094 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to execute a query")) 1095 1096 //There should be 7 results for size >= 3 and size <= 10 and not 7 1097 testutil.AssertEquals(t, len(*queryResult), 7) 1098 1099 //Test query with leading operator and array of objects ---------------------------------------------------------- 1100 queryString = "{\"selector\":{\"$and\":[{\"size\":{\"$gte\":2}},{\"size\":{\"$lte\":10}},{\"$nor\":[{\"size\":3},{\"size\":5},{\"size\":7}]}]}}" 1101 1102 queryResult, err = db.QueryDocuments(queryString) 1103 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to execute a query")) 1104 1105 //There should be 6 results for size >= 2 and size <= 10 and not 3,5 or 7 1106 testutil.AssertEquals(t, len(*queryResult), 6) 1107 1108 //Test a range query --------------------------------------------------------------------------------------------- 1109 queryResult, err = db.ReadDocRange("marble02", "marble06", 10000, 0) 1110 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to execute a range query")) 1111 1112 //There should be 4 results 1113 testutil.AssertEquals(t, len(*queryResult), 4) 1114 1115 //Test query with for tom ------------------------------------------------------------------- 1116 queryString = "{\"selector\":{\"owner\":{\"$eq\":\"tom\"}}}" 1117 1118 queryResult, err = db.QueryDocuments(queryString) 1119 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to execute a query")) 1120 1121 //There should be 8 results for owner="tom" 1122 testutil.AssertEquals(t, len(*queryResult), 8) 1123 1124 //Test query with for tom with limit ------------------------------------------------------------------- 1125 queryString = "{\"selector\":{\"owner\":{\"$eq\":\"tom\"}},\"limit\":2}" 1126 1127 queryResult, err = db.QueryDocuments(queryString) 1128 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to execute a query")) 1129 1130 //There should be 2 results for owner="tom" with a limit of 2 1131 testutil.AssertEquals(t, len(*queryResult), 2) 1132 1133 //Test query with invalid index ------------------------------------------------------------------- 1134 queryString = "{\"selector\":{\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\",\"indexOwner\"]}" 1135 1136 _, err = db.QueryDocuments(queryString) 1137 testutil.AssertError(t, err, fmt.Sprintf("Error should have been thrown for an invalid index")) 1138 1139 } 1140 } 1141 } 1142 1143 func TestBatchBatchOperations(t *testing.T) { 1144 1145 if ledgerconfig.IsCouchDBEnabled() { 1146 1147 byteJSON01 := []byte(`{"_id":"marble01","asset_name":"marble01","color":"blue","size":"1","owner":"jerry"}`) 1148 byteJSON02 := []byte(`{"_id":"marble02","asset_name":"marble02","color":"red","size":"2","owner":"tom"}`) 1149 byteJSON03 := []byte(`{"_id":"marble03","asset_name":"marble03","color":"green","size":"3","owner":"jerry"}`) 1150 byteJSON04 := []byte(`{"_id":"marble04","asset_name":"marble04","color":"purple","size":"4","owner":"tom"}`) 1151 byteJSON05 := []byte(`{"_id":"marble05","asset_name":"marble05","color":"blue","size":"5","owner":"jerry"}`) 1152 1153 attachment1 := &Attachment{} 1154 attachment1.AttachmentBytes = []byte(`marble01 - test attachment`) 1155 attachment1.ContentType = "application/octet-stream" 1156 attachment1.Name = "data" 1157 attachments1 := []*Attachment{} 1158 attachments1 = append(attachments1, attachment1) 1159 1160 attachment2 := &Attachment{} 1161 attachment2.AttachmentBytes = []byte(`marble02 - test attachment`) 1162 attachment2.ContentType = "application/octet-stream" 1163 attachment2.Name = "data" 1164 attachments2 := []*Attachment{} 1165 attachments2 = append(attachments2, attachment2) 1166 1167 attachment3 := &Attachment{} 1168 attachment3.AttachmentBytes = []byte(`marble03 - test attachment`) 1169 attachment3.ContentType = "application/octet-stream" 1170 attachment3.Name = "data" 1171 attachments3 := []*Attachment{} 1172 attachments3 = append(attachments3, attachment3) 1173 1174 attachment4 := &Attachment{} 1175 attachment4.AttachmentBytes = []byte(`marble04 - test attachment`) 1176 attachment4.ContentType = "application/octet-stream" 1177 attachment4.Name = "data" 1178 attachments4 := []*Attachment{} 1179 attachments4 = append(attachments4, attachment4) 1180 1181 attachment5 := &Attachment{} 1182 attachment5.AttachmentBytes = []byte(`marble05 - test attachment`) 1183 attachment5.ContentType = "application/octet-stream" 1184 attachment5.Name = "data" 1185 attachments5 := []*Attachment{} 1186 attachments5 = append(attachments5, attachment5) 1187 1188 database := "testbatch" 1189 err := cleanup(database) 1190 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 1191 defer cleanup(database) 1192 1193 //create a new instance and database object -------------------------------------------------------- 1194 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 1195 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 1196 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 1197 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 1198 1199 //create a new database 1200 _, errdb := db.CreateDatabaseIfNotExist() 1201 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database")) 1202 1203 batchUpdateDocs := []*CouchDoc{} 1204 1205 value1 := &CouchDoc{JSONValue: byteJSON01, Attachments: attachments1} 1206 value2 := &CouchDoc{JSONValue: byteJSON02, Attachments: attachments2} 1207 value3 := &CouchDoc{JSONValue: byteJSON03, Attachments: attachments3} 1208 value4 := &CouchDoc{JSONValue: byteJSON04, Attachments: attachments4} 1209 value5 := &CouchDoc{JSONValue: byteJSON05, Attachments: attachments5} 1210 1211 batchUpdateDocs = append(batchUpdateDocs, value1) 1212 batchUpdateDocs = append(batchUpdateDocs, value2) 1213 batchUpdateDocs = append(batchUpdateDocs, value3) 1214 batchUpdateDocs = append(batchUpdateDocs, value4) 1215 batchUpdateDocs = append(batchUpdateDocs, value5) 1216 1217 batchUpdateResp, err := db.BatchUpdateDocuments(batchUpdateDocs) 1218 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to update a batch of documents")) 1219 1220 //check to make sure each batch update response was successful 1221 for _, updateDoc := range batchUpdateResp { 1222 testutil.AssertEquals(t, updateDoc.Ok, true) 1223 } 1224 1225 //---------------------------------------------- 1226 //Test Retrieve JSON 1227 dbGetResp, _, geterr := db.ReadDoc("marble01") 1228 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when attempting read a document")) 1229 1230 assetResp := &Asset{} 1231 geterr = json.Unmarshal(dbGetResp.JSONValue, &assetResp) 1232 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document")) 1233 //Verify the owner retrieved matches 1234 testutil.AssertEquals(t, assetResp.Owner, "jerry") 1235 1236 //---------------------------------------------- 1237 //Test retrieve binary 1238 dbGetResp, _, geterr = db.ReadDoc("marble03") 1239 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when attempting read a document")) 1240 //Retrieve the attachments 1241 attachments := dbGetResp.Attachments 1242 //Only one was saved, so take the first 1243 retrievedAttachment := attachments[0] 1244 //Verify the text matches 1245 testutil.AssertEquals(t, attachment3.AttachmentBytes, retrievedAttachment.AttachmentBytes) 1246 //---------------------------------------------- 1247 //Test Bad Updates 1248 batchUpdateDocs = []*CouchDoc{} 1249 batchUpdateDocs = append(batchUpdateDocs, value1) 1250 batchUpdateDocs = append(batchUpdateDocs, value2) 1251 batchUpdateResp, err = db.BatchUpdateDocuments(batchUpdateDocs) 1252 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to update a batch of documents")) 1253 //No revision was provided, so these two updates should fail 1254 //Verify that the "Ok" field is returned as false 1255 for _, updateDoc := range batchUpdateResp { 1256 testutil.AssertEquals(t, updateDoc.Ok, false) 1257 testutil.AssertEquals(t, updateDoc.Error, updateDocumentConflictError) 1258 testutil.AssertEquals(t, updateDoc.Reason, updateDocumentConflictReason) 1259 } 1260 1261 //---------------------------------------------- 1262 //Test Batch Retrieve Keys and Update 1263 1264 var keys []string 1265 1266 keys = append(keys, "marble01") 1267 keys = append(keys, "marble03") 1268 1269 batchRevs, err := db.BatchRetrieveIDRevision(keys) 1270 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting retrieve revisions")) 1271 1272 batchUpdateDocs = []*CouchDoc{} 1273 1274 //iterate through the revision docs 1275 for _, revdoc := range batchRevs { 1276 if revdoc.ID == "marble01" { 1277 //update the json with the rev and add to the batch 1278 marble01Doc := addRevisionAndDeleteStatus(revdoc.Rev, byteJSON01, false) 1279 batchUpdateDocs = append(batchUpdateDocs, &CouchDoc{JSONValue: marble01Doc, Attachments: attachments1}) 1280 } 1281 1282 if revdoc.ID == "marble03" { 1283 //update the json with the rev and add to the batch 1284 marble03Doc := addRevisionAndDeleteStatus(revdoc.Rev, byteJSON03, false) 1285 batchUpdateDocs = append(batchUpdateDocs, &CouchDoc{JSONValue: marble03Doc, Attachments: attachments3}) 1286 } 1287 } 1288 1289 //Update couchdb with the batch 1290 batchUpdateResp, err = db.BatchUpdateDocuments(batchUpdateDocs) 1291 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to update a batch of documents")) 1292 //check to make sure each batch update response was successful 1293 for _, updateDoc := range batchUpdateResp { 1294 testutil.AssertEquals(t, updateDoc.Ok, true) 1295 } 1296 1297 //---------------------------------------------- 1298 //Test Batch Delete 1299 1300 keys = []string{} 1301 1302 keys = append(keys, "marble02") 1303 keys = append(keys, "marble04") 1304 1305 batchRevs, err = db.BatchRetrieveIDRevision(keys) 1306 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting retrieve revisions")) 1307 1308 batchUpdateDocs = []*CouchDoc{} 1309 1310 //iterate through the revision docs 1311 for _, revdoc := range batchRevs { 1312 if revdoc.ID == "marble02" { 1313 //update the json with the rev and add to the batch 1314 marble02Doc := addRevisionAndDeleteStatus(revdoc.Rev, byteJSON02, true) 1315 batchUpdateDocs = append(batchUpdateDocs, &CouchDoc{JSONValue: marble02Doc, Attachments: attachments1}) 1316 } 1317 if revdoc.ID == "marble04" { 1318 //update the json with the rev and add to the batch 1319 marble04Doc := addRevisionAndDeleteStatus(revdoc.Rev, byteJSON04, true) 1320 batchUpdateDocs = append(batchUpdateDocs, &CouchDoc{JSONValue: marble04Doc, Attachments: attachments3}) 1321 } 1322 } 1323 1324 //Update couchdb with the batch 1325 batchUpdateResp, err = db.BatchUpdateDocuments(batchUpdateDocs) 1326 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to update a batch of documents")) 1327 1328 //check to make sure each batch update response was successful 1329 for _, updateDoc := range batchUpdateResp { 1330 testutil.AssertEquals(t, updateDoc.Ok, true) 1331 } 1332 1333 //Retrieve the test document 1334 dbGetResp, _, geterr = db.ReadDoc("marble02") 1335 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document")) 1336 1337 //assert the value was deleted 1338 testutil.AssertNil(t, dbGetResp) 1339 1340 //Retrieve the test document 1341 dbGetResp, _, geterr = db.ReadDoc("marble04") 1342 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document")) 1343 1344 //assert the value was deleted 1345 testutil.AssertNil(t, dbGetResp) 1346 } 1347 } 1348 1349 //addRevisionAndDeleteStatus adds keys for version and chaincodeID to the JSON value 1350 func addRevisionAndDeleteStatus(revision string, value []byte, deleted bool) []byte { 1351 1352 //create a version mapping 1353 jsonMap := make(map[string]interface{}) 1354 1355 json.Unmarshal(value, &jsonMap) 1356 1357 //add the revision 1358 if revision != "" { 1359 jsonMap["_rev"] = revision 1360 } 1361 1362 //If this record is to be deleted, set the "_deleted" property to true 1363 if deleted { 1364 jsonMap["_deleted"] = true 1365 } 1366 //marshal the data to a byte array 1367 returnJSON, _ := json.Marshal(jsonMap) 1368 1369 return returnJSON 1370 1371 }