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