github.com/true-sqn/fabric@v2.1.1+incompatible/core/ledger/util/couchdb/couchdb_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package couchdb 8 9 import ( 10 "context" 11 "encoding/json" 12 "fmt" 13 "net/http" 14 "net/url" 15 "os" 16 "strings" 17 "testing" 18 "time" 19 "unicode/utf8" 20 21 "github.com/hyperledger/fabric/common/flogging" 22 "github.com/hyperledger/fabric/common/metrics/disabled" 23 "github.com/hyperledger/fabric/core/ledger/util/couchdbtest" 24 "github.com/stretchr/testify/assert" 25 "github.com/stretchr/testify/require" 26 ) 27 28 const badConnectURL = "couchdb:5990" 29 const badParseConnectURL = "http://host.com|5432" 30 const updateDocumentConflictError = "conflict" 31 const updateDocumentConflictReason = "Document update conflict." 32 33 func cleanup(database string) error { 34 //create a new connection 35 couchInstance, err := CreateCouchInstance(testConfig(), &disabled.Provider{}) 36 if err != nil { 37 fmt.Println("Unexpected error", err) 38 return err 39 } 40 db := CouchDatabase{CouchInstance: couchInstance, DBName: database} 41 //drop the test database 42 db.DropDatabase() 43 return nil 44 } 45 46 type Asset struct { 47 ID string `json:"_id"` 48 Rev string `json:"_rev"` 49 AssetName string `json:"asset_name"` 50 Color string `json:"color"` 51 Size string `json:"size"` 52 Owner string `json:"owner"` 53 } 54 55 var assetJSON = []byte(`{"asset_name":"marble1","color":"blue","size":"35","owner":"jerry"}`) 56 57 var testAddress string 58 var cleanupCouchDB = func() {} 59 60 func testConfig() *Config { 61 return &Config{ 62 Address: testAddress, 63 Username: "", 64 Password: "", 65 MaxRetries: 3, 66 MaxRetriesOnStartup: 20, 67 RequestTimeout: 35 * time.Second, 68 CreateGlobalChangesDB: true, 69 } 70 } 71 72 func TestMain(m *testing.M) { 73 //set the logging level to DEBUG to test debug only code 74 flogging.ActivateSpec("couchdb=debug") 75 76 rc := m.Run() 77 cleanupCouchDB() 78 79 os.Exit(rc) 80 } 81 82 func startCouchDB() { 83 if testAddress == "" { 84 testAddress, cleanupCouchDB = couchdbtest.CouchDBSetup((nil)) 85 } 86 } 87 88 func TestDBBadConnectionDef(t *testing.T) { 89 startCouchDB() 90 config := testConfig() 91 config.Address = badParseConnectURL 92 _, err := CreateCouchInstance(config, &disabled.Provider{}) 93 assert.Error(t, err, "Did not receive error when trying to create database connection definition with a bad hostname") 94 } 95 96 func TestEncodePathElement(t *testing.T) { 97 98 encodedString := encodePathElement("testelement") 99 assert.Equal(t, "testelement", encodedString) 100 101 encodedString = encodePathElement("test element") 102 assert.Equal(t, "test%20element", encodedString) 103 104 encodedString = encodePathElement("/test element") 105 assert.Equal(t, "%2Ftest%20element", encodedString) 106 107 encodedString = encodePathElement("/test element:") 108 assert.Equal(t, "%2Ftest%20element:", encodedString) 109 110 encodedString = encodePathElement("/test+ element:") 111 assert.Equal(t, "%2Ftest%2B%20element:", encodedString) 112 113 } 114 115 func TestHealthCheck(t *testing.T) { 116 startCouchDB() 117 client := &http.Client{} 118 119 config := testConfig() 120 config.Address = testAddress + "1" 121 badCouchDBInstance := CouchInstance{ 122 conf: config, 123 client: client, 124 stats: newStats(&disabled.Provider{}), 125 } 126 err := badCouchDBInstance.HealthCheck(context.Background()) 127 assert.Error(t, err, "Health check should result in an error if unable to connect to couch db") 128 assert.Contains(t, err.Error(), "failed to connect to couch db") 129 130 //Create a good couchdb instance 131 goodCouchDBInstance := CouchInstance{ 132 conf: testConfig(), 133 client: client, 134 stats: newStats(&disabled.Provider{}), 135 } 136 err = goodCouchDBInstance.HealthCheck(context.Background()) 137 assert.NoError(t, err) 138 } 139 140 func TestBadCouchDBInstance(t *testing.T) { 141 142 client := &http.Client{} 143 144 //Create a bad couchdb instance 145 badCouchDBInstance := CouchInstance{ 146 conf: &Config{ 147 Address: badParseConnectURL, 148 Username: "", 149 Password: "", 150 MaxRetries: 3, 151 MaxRetriesOnStartup: 10, 152 RequestTimeout: 30 * time.Second, 153 }, 154 client: client, 155 stats: newStats(&disabled.Provider{}), 156 } 157 158 //Create a bad CouchDatabase 159 badDB := CouchDatabase{&badCouchDBInstance, "baddb", 1} 160 161 //Test CreateCouchDatabase with bad connection 162 _, err := CreateCouchDatabase(&badCouchDBInstance, "baddbtest") 163 assert.Error(t, err, "Error should have been thrown with CreateCouchDatabase and invalid connection") 164 165 //Test CreateSystemDatabasesIfNotExist with bad connection 166 err = CreateSystemDatabasesIfNotExist(&badCouchDBInstance) 167 assert.Error(t, err, "Error should have been thrown with CreateSystemDatabasesIfNotExist and invalid connection") 168 169 //Test CreateDatabaseIfNotExist with bad connection 170 err = badDB.CreateDatabaseIfNotExist() 171 assert.Error(t, err, "Error should have been thrown with CreateDatabaseIfNotExist and invalid connection") 172 173 //Test GetDatabaseInfo with bad connection 174 _, _, err = badDB.GetDatabaseInfo() 175 assert.Error(t, err, "Error should have been thrown with GetDatabaseInfo and invalid connection") 176 177 //Test VerifyCouchConfig with bad connection 178 _, _, err = badCouchDBInstance.VerifyCouchConfig() 179 assert.Error(t, err, "Error should have been thrown with VerifyCouchConfig and invalid connection") 180 181 //Test EnsureFullCommit with bad connection 182 _, err = badDB.EnsureFullCommit() 183 assert.Error(t, err, "Error should have been thrown with EnsureFullCommit and invalid connection") 184 185 //Test DropDatabase with bad connection 186 _, err = badDB.DropDatabase() 187 assert.Error(t, err, "Error should have been thrown with DropDatabase and invalid connection") 188 189 //Test ReadDoc with bad connection 190 _, _, err = badDB.ReadDoc("1") 191 assert.Error(t, err, "Error should have been thrown with ReadDoc and invalid connection") 192 193 //Test SaveDoc with bad connection 194 _, err = badDB.SaveDoc("1", "1", nil) 195 assert.Error(t, err, "Error should have been thrown with SaveDoc and invalid connection") 196 197 //Test DeleteDoc with bad connection 198 err = badDB.DeleteDoc("1", "1") 199 assert.Error(t, err, "Error should have been thrown with DeleteDoc and invalid connection") 200 201 //Test ReadDocRange with bad connection 202 _, _, err = badDB.ReadDocRange("1", "2", 1000) 203 assert.Error(t, err, "Error should have been thrown with ReadDocRange and invalid connection") 204 205 //Test QueryDocuments with bad connection 206 _, _, err = badDB.QueryDocuments("1") 207 assert.Error(t, err, "Error should have been thrown with QueryDocuments and invalid connection") 208 209 //Test BatchRetrieveDocumentMetadata with bad connection 210 _, err = badDB.BatchRetrieveDocumentMetadata(nil) 211 assert.Error(t, err, "Error should have been thrown with BatchRetrieveDocumentMetadata and invalid connection") 212 213 //Test BatchUpdateDocuments with bad connection 214 _, err = badDB.BatchUpdateDocuments(nil) 215 assert.Error(t, err, "Error should have been thrown with BatchUpdateDocuments and invalid connection") 216 217 //Test ListIndex with bad connection 218 _, err = badDB.ListIndex() 219 assert.Error(t, err, "Error should have been thrown with ListIndex and invalid connection") 220 221 //Test CreateIndex with bad connection 222 _, err = badDB.CreateIndex("") 223 assert.Error(t, err, "Error should have been thrown with CreateIndex and invalid connection") 224 225 //Test DeleteIndex with bad connection 226 err = badDB.DeleteIndex("", "") 227 assert.Error(t, err, "Error should have been thrown with DeleteIndex and invalid connection") 228 229 } 230 231 func TestDBCreateSaveWithoutRevision(t *testing.T) { 232 startCouchDB() 233 database := "testdbcreatesavewithoutrevision" 234 err := cleanup(database) 235 assert.NoError(t, err, "Error when trying to cleanup Error: %s", err) 236 defer cleanup(database) 237 238 //create a new instance and database object 239 couchInstance, err := CreateCouchInstance(testConfig(), &disabled.Provider{}) 240 assert.NoError(t, err, "Error when trying to create couch instance") 241 db := CouchDatabase{CouchInstance: couchInstance, DBName: database} 242 243 //create a new database 244 errdb := db.CreateDatabaseIfNotExist() 245 assert.NoError(t, errdb, "Error when trying to create database") 246 247 //Save the test document 248 _, saveerr := db.SaveDoc("2", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 249 assert.NoError(t, saveerr, "Error when trying to save a document") 250 251 } 252 253 func TestDBCreateEnsureFullCommit(t *testing.T) { 254 startCouchDB() 255 database := "testdbensurefullcommit" 256 err := cleanup(database) 257 assert.NoError(t, err, "Error when trying to cleanup Error: %s", err) 258 defer cleanup(database) 259 260 //create a new instance and database object 261 couchInstance, err := CreateCouchInstance(testConfig(), &disabled.Provider{}) 262 assert.NoError(t, err, "Error when trying to create couch instance") 263 db := CouchDatabase{CouchInstance: couchInstance, DBName: database} 264 265 //create a new database 266 errdb := db.CreateDatabaseIfNotExist() 267 assert.NoError(t, errdb, "Error when trying to create database") 268 269 //Save the test document 270 _, saveerr := db.SaveDoc("2", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 271 assert.NoError(t, saveerr, "Error when trying to save a document") 272 273 //Ensure a full commit 274 _, commiterr := db.EnsureFullCommit() 275 assert.NoError(t, commiterr, "Error when trying to ensure a full commit") 276 } 277 278 func TestIsEmpty(t *testing.T) { 279 startCouchDB() 280 couchInstance, err := CreateCouchInstance(testConfig(), &disabled.Provider{}) 281 assert.NoError(t, err) 282 283 isEmpty, err := couchInstance.IsEmpty(nil) 284 require.NoError(t, err) 285 require.True(t, isEmpty) 286 287 testdbs := []string{"testdb1", "testdb2"} 288 defer func() { 289 for _, d := range testdbs { 290 cleanup(d) 291 } 292 }() 293 294 for _, d := range testdbs { 295 db := CouchDatabase{CouchInstance: couchInstance, DBName: d} 296 require.NoError(t, db.CreateDatabaseIfNotExist()) 297 } 298 isEmpty, err = couchInstance.IsEmpty(nil) 299 require.NoError(t, err) 300 require.False(t, isEmpty) 301 302 ignore := []string{"testdb1"} 303 isEmpty, err = couchInstance.IsEmpty(ignore) 304 require.NoError(t, err) 305 require.False(t, isEmpty) 306 307 ignore = []string{"testdb1", "testdb2"} 308 isEmpty, err = couchInstance.IsEmpty(ignore) 309 require.NoError(t, err) 310 require.True(t, isEmpty) 311 312 couchInstance.conf.Address = "junk" 313 couchInstance.conf.MaxRetries = 0 314 isEmpty, err = couchInstance.IsEmpty(ignore) 315 require.Error(t, err) 316 require.Regexp(t, `unable to connect to CouchDB, check the hostname and port: http error calling couchdb: Get "?http://junk/_all_dbs"?`, err.Error()) 317 } 318 319 func TestDBBadDatabaseName(t *testing.T) { 320 startCouchDB() 321 //create a new instance and database object using a valid database name mixed case 322 couchInstance, err := CreateCouchInstance(testConfig(), &disabled.Provider{}) 323 assert.NoError(t, err, "Error when trying to create couch instance") 324 _, dberr := CreateCouchDatabase(couchInstance, "testDB") 325 assert.Error(t, dberr, "Error should have been thrown for an invalid db name") 326 327 //create a new instance and database object using a valid database name letters and numbers 328 couchInstance, err = CreateCouchInstance(testConfig(), &disabled.Provider{}) 329 assert.NoError(t, err, "Error when trying to create couch instance") 330 _, dberr = CreateCouchDatabase(couchInstance, "test132") 331 assert.NoError(t, dberr, "Error when testing a valid database name") 332 333 //create a new instance and database object using a valid database name - special characters 334 couchInstance, err = CreateCouchInstance(testConfig(), &disabled.Provider{}) 335 assert.NoError(t, err, "Error when trying to create couch instance") 336 _, dberr = CreateCouchDatabase(couchInstance, "test1234~!@#$%^&*()[]{}.") 337 assert.Error(t, dberr, "Error should have been thrown for an invalid db name") 338 339 //create a new instance and database object using a invalid database name - too long /* 340 couchInstance, err = CreateCouchInstance(testConfig(), &disabled.Provider{}) 341 assert.NoError(t, err, "Error when trying to create couch instance") 342 _, dberr = CreateCouchDatabase(couchInstance, "a12345678901234567890123456789012345678901234"+ 343 "56789012345678901234567890123456789012345678901234567890123456789012345678901234567890"+ 344 "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456"+ 345 "78901234567890123456789012345678901234567890") 346 assert.Error(t, dberr, "Error should have been thrown for invalid database name") 347 348 } 349 350 func TestDBBadConnection(t *testing.T) { 351 startCouchDB() 352 //create a new instance and database object 353 //Limit the maxRetriesOnStartup to 3 in order to reduce time for the failure 354 config := testConfig() 355 config.Address = badConnectURL 356 config.MaxRetriesOnStartup = 3 357 _, err := CreateCouchInstance(config, &disabled.Provider{}) 358 assert.Error(t, err, "Error should have been thrown for a bad connection") 359 } 360 361 func TestBadDBCredentials(t *testing.T) { 362 startCouchDB() 363 database := "testdbbadcredentials" 364 err := cleanup(database) 365 assert.NoError(t, err, "Error when trying to cleanup Error: %s", err) 366 defer cleanup(database) 367 368 badConfig := testConfig() 369 badConfig.Username = "fred" 370 badConfig.Password = "fred" 371 //create a new instance and database object 372 _, err = CreateCouchInstance(badConfig, &disabled.Provider{}) 373 assert.Error(t, err, "Error should have been thrown for bad credentials") 374 375 } 376 377 func TestDBCreateDatabaseAndPersist(t *testing.T) { 378 startCouchDB() 379 380 //Test create and persist with default configured maxRetries 381 testDBCreateDatabaseAndPersist(t, testConfig().MaxRetries) 382 383 //Test create and persist with 0 retries 384 testDBCreateDatabaseAndPersist(t, 0) 385 386 //Test batch operations with default configured maxRetries 387 testBatchBatchOperations(t, testConfig().MaxRetries) 388 389 //Test batch operations with 0 retries 390 testBatchBatchOperations(t, 0) 391 392 } 393 394 func testDBCreateDatabaseAndPersist(t *testing.T, maxRetries int) { 395 396 database := "testdbcreatedatabaseandpersist" 397 err := cleanup(database) 398 assert.NoError(t, err, "Error when trying to cleanup Error: %s", err) 399 defer cleanup(database) 400 401 //create a new instance and database object 402 couchInstance, err := CreateCouchInstance(testConfig(), &disabled.Provider{}) 403 assert.NoError(t, err, "Error when trying to create couch instance") 404 db := CouchDatabase{CouchInstance: couchInstance, DBName: database} 405 406 //create a new database 407 errdb := db.CreateDatabaseIfNotExist() 408 assert.NoError(t, errdb, "Error when trying to create database") 409 410 //Retrieve the info for the new database and make sure the name matches 411 dbResp, _, errdb := db.GetDatabaseInfo() 412 assert.NoError(t, errdb, "Error when trying to retrieve database information") 413 assert.Equal(t, database, dbResp.DbName) 414 415 //Save the test document 416 _, saveerr := db.SaveDoc("idWith/slash", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 417 assert.NoError(t, saveerr, "Error when trying to save a document") 418 419 //Retrieve the test document 420 dbGetResp, _, geterr := db.ReadDoc("idWith/slash") 421 assert.NoError(t, geterr, "Error when trying to retrieve a document") 422 423 //Unmarshal the document to Asset structure 424 assetResp := &Asset{} 425 geterr = json.Unmarshal(dbGetResp.JSONValue, &assetResp) 426 assert.NoError(t, geterr, "Error when trying to retrieve a document") 427 428 //Verify the owner retrieved matches 429 assert.Equal(t, "jerry", assetResp.Owner) 430 431 //Save the test document 432 _, saveerr = db.SaveDoc("1", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 433 assert.NoError(t, saveerr, "Error when trying to save a document") 434 435 //Retrieve the test document 436 dbGetResp, _, geterr = db.ReadDoc("1") 437 assert.NoError(t, geterr, "Error when trying to retrieve a document") 438 439 //Unmarshal the document to Asset structure 440 assetResp = &Asset{} 441 geterr = json.Unmarshal(dbGetResp.JSONValue, &assetResp) 442 assert.NoError(t, geterr, "Error when trying to retrieve a document") 443 444 //Verify the owner retrieved matches 445 assert.Equal(t, "jerry", assetResp.Owner) 446 447 //Change owner to bob 448 assetResp.Owner = "bob" 449 450 //create a byte array of the JSON 451 assetDocUpdated, _ := json.Marshal(assetResp) 452 453 //Save the updated test document 454 _, saveerr = db.SaveDoc("1", "", &CouchDoc{JSONValue: assetDocUpdated, Attachments: nil}) 455 assert.NoError(t, saveerr, "Error when trying to save the updated document") 456 457 //Retrieve the updated test document 458 dbGetResp, _, geterr = db.ReadDoc("1") 459 assert.NoError(t, geterr, "Error when trying to retrieve a document") 460 461 //Unmarshal the document to Asset structure 462 assetResp = &Asset{} 463 json.Unmarshal(dbGetResp.JSONValue, &assetResp) 464 465 //Assert that the update was saved and retrieved 466 assert.Equal(t, "bob", assetResp.Owner) 467 468 testBytes2 := []byte(`test attachment 2`) 469 470 attachment2 := &AttachmentInfo{} 471 attachment2.AttachmentBytes = testBytes2 472 attachment2.ContentType = "application/octet-stream" 473 attachment2.Name = "data" 474 attachments2 := []*AttachmentInfo{} 475 attachments2 = append(attachments2, attachment2) 476 477 //Save the test document with an attachment 478 _, saveerr = db.SaveDoc("2", "", &CouchDoc{JSONValue: nil, Attachments: attachments2}) 479 assert.NoError(t, saveerr, "Error when trying to save a document") 480 481 //Retrieve the test document with attachments 482 dbGetResp, _, geterr = db.ReadDoc("2") 483 assert.NoError(t, geterr, "Error when trying to retrieve a document") 484 485 //verify the text from the attachment is correct 486 testattach := dbGetResp.Attachments[0].AttachmentBytes 487 assert.Equal(t, testBytes2, testattach) 488 489 testBytes3 := []byte{} 490 491 attachment3 := &AttachmentInfo{} 492 attachment3.AttachmentBytes = testBytes3 493 attachment3.ContentType = "application/octet-stream" 494 attachment3.Name = "data" 495 attachments3 := []*AttachmentInfo{} 496 attachments3 = append(attachments3, attachment3) 497 498 //Save the test document with a zero length attachment 499 _, saveerr = db.SaveDoc("3", "", &CouchDoc{JSONValue: nil, Attachments: attachments3}) 500 assert.NoError(t, saveerr, "Error when trying to save a document") 501 502 //Retrieve the test document with attachments 503 dbGetResp, _, geterr = db.ReadDoc("3") 504 assert.NoError(t, geterr, "Error when trying to retrieve a document") 505 506 //verify the text from the attachment is correct, zero bytes 507 testattach = dbGetResp.Attachments[0].AttachmentBytes 508 assert.Equal(t, testBytes3, testattach) 509 510 testBytes4a := []byte(`test attachment 4a`) 511 attachment4a := &AttachmentInfo{} 512 attachment4a.AttachmentBytes = testBytes4a 513 attachment4a.ContentType = "application/octet-stream" 514 attachment4a.Name = "data1" 515 516 testBytes4b := []byte(`test attachment 4b`) 517 attachment4b := &AttachmentInfo{} 518 attachment4b.AttachmentBytes = testBytes4b 519 attachment4b.ContentType = "application/octet-stream" 520 attachment4b.Name = "data2" 521 522 attachments4 := []*AttachmentInfo{} 523 attachments4 = append(attachments4, attachment4a) 524 attachments4 = append(attachments4, attachment4b) 525 526 //Save the updated test document with multiple attachments 527 _, saveerr = db.SaveDoc("4", "", &CouchDoc{JSONValue: assetJSON, Attachments: attachments4}) 528 assert.NoError(t, saveerr, "Error when trying to save the updated document") 529 530 //Retrieve the test document with attachments 531 dbGetResp, _, geterr = db.ReadDoc("4") 532 assert.NoError(t, geterr, "Error when trying to retrieve a document") 533 534 for _, attach4 := range dbGetResp.Attachments { 535 536 currentName := attach4.Name 537 if currentName == "data1" { 538 assert.Equal(t, testBytes4a, attach4.AttachmentBytes) 539 } 540 if currentName == "data2" { 541 assert.Equal(t, testBytes4b, attach4.AttachmentBytes) 542 } 543 544 } 545 546 testBytes5a := []byte(`test attachment 5a`) 547 attachment5a := &AttachmentInfo{} 548 attachment5a.AttachmentBytes = testBytes5a 549 attachment5a.ContentType = "application/octet-stream" 550 attachment5a.Name = "data1" 551 552 testBytes5b := []byte{} 553 attachment5b := &AttachmentInfo{} 554 attachment5b.AttachmentBytes = testBytes5b 555 attachment5b.ContentType = "application/octet-stream" 556 attachment5b.Name = "data2" 557 558 attachments5 := []*AttachmentInfo{} 559 attachments5 = append(attachments5, attachment5a) 560 attachments5 = append(attachments5, attachment5b) 561 562 //Save the updated test document with multiple attachments and zero length attachments 563 _, saveerr = db.SaveDoc("5", "", &CouchDoc{JSONValue: assetJSON, Attachments: attachments5}) 564 assert.NoError(t, saveerr, "Error when trying to save the updated document") 565 566 //Retrieve the test document with attachments 567 dbGetResp, _, geterr = db.ReadDoc("5") 568 assert.NoError(t, geterr, "Error when trying to retrieve a document") 569 570 for _, attach5 := range dbGetResp.Attachments { 571 572 currentName := attach5.Name 573 if currentName == "data1" { 574 assert.Equal(t, testBytes5a, attach5.AttachmentBytes) 575 } 576 if currentName == "data2" { 577 assert.Equal(t, testBytes5b, attach5.AttachmentBytes) 578 } 579 580 } 581 582 //Attempt to save the document with an invalid id 583 _, saveerr = db.SaveDoc(string([]byte{0xff, 0xfe, 0xfd}), "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 584 assert.Error(t, saveerr, "Error should have been thrown when saving a document with an invalid ID") 585 586 //Attempt to read a document with an invalid id 587 _, _, readerr := db.ReadDoc(string([]byte{0xff, 0xfe, 0xfd})) 588 assert.Error(t, readerr, "Error should have been thrown when reading a document with an invalid ID") 589 590 //Drop the database 591 _, errdbdrop := db.DropDatabase() 592 assert.NoError(t, errdbdrop, "Error dropping database") 593 594 //Make sure an error is thrown for getting info for a missing database 595 _, _, errdbinfo := db.GetDatabaseInfo() 596 assert.Error(t, errdbinfo, "Error should have been thrown for missing database") 597 598 //Attempt to save a document to a deleted database 599 _, saveerr = db.SaveDoc("6", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 600 assert.Error(t, saveerr, "Error should have been thrown while attempting to save to a deleted database") 601 602 //Attempt to read from a deleted database 603 _, _, geterr = db.ReadDoc("6") 604 assert.NoError(t, geterr, "Error should not have been thrown for a missing database, nil value is returned") 605 606 } 607 608 func TestDBRequestTimeout(t *testing.T) { 609 startCouchDB() 610 database := "testdbrequesttimeout" 611 err := cleanup(database) 612 assert.NoError(t, err, "Error when trying to cleanup Error: %s", err) 613 defer cleanup(database) 614 615 //create an impossibly short timeout 616 impossibleTimeout := time.Nanosecond 617 618 //create a new instance and database object with a timeout that will fail 619 //Also use a maxRetriesOnStartup=3 to reduce the number of retries 620 config := testConfig() 621 config.MaxRetriesOnStartup = 3 622 config.RequestTimeout = impossibleTimeout 623 _, err = CreateCouchInstance(config, &disabled.Provider{}) 624 assert.Error(t, err, "Error should have been thown while trying to create a couchdb instance with a connection timeout") 625 626 //create a new instance and database object 627 config = testConfig() 628 config.MaxRetries = -1 629 config.MaxRetriesOnStartup = 3 630 _, err = CreateCouchInstance(config, &disabled.Provider{}) 631 assert.Error(t, err, "Error should have been thrown while attempting to create a database") 632 633 } 634 635 func TestDBTimeoutConflictRetry(t *testing.T) { 636 startCouchDB() 637 database := "testdbtimeoutretry" 638 err := cleanup(database) 639 assert.NoError(t, err, "Error when trying to cleanup Error: %s", err) 640 defer cleanup(database) 641 642 //create a new instance and database object 643 config := testConfig() 644 config.MaxRetriesOnStartup = 3 645 couchInstance, err := CreateCouchInstance(config, &disabled.Provider{}) 646 assert.NoError(t, err, "Error when trying to create couch instance") 647 db := CouchDatabase{CouchInstance: couchInstance, DBName: database} 648 649 //create a new database 650 errdb := db.CreateDatabaseIfNotExist() 651 assert.NoError(t, errdb, "Error when trying to create database") 652 653 //Retrieve the info for the new database and make sure the name matches 654 dbResp, _, errdb := db.GetDatabaseInfo() 655 assert.NoError(t, errdb, "Error when trying to retrieve database information") 656 assert.Equal(t, database, dbResp.DbName) 657 658 //Save the test document 659 _, saveerr := db.SaveDoc("1", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 660 assert.NoError(t, saveerr, "Error when trying to save a document") 661 662 //Retrieve the test document 663 _, _, geterr := db.ReadDoc("1") 664 assert.NoError(t, geterr, "Error when trying to retrieve a document") 665 666 //Save the test document with an invalid rev. This should cause a retry 667 _, saveerr = db.SaveDoc("1", "1-11111111111111111111111111111111", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 668 assert.NoError(t, saveerr, "Error when trying to save a document with a revision conflict") 669 670 //Delete the test document with an invalid rev. This should cause a retry 671 deleteerr := db.DeleteDoc("1", "1-11111111111111111111111111111111") 672 assert.NoError(t, deleteerr, "Error when trying to delete a document with a revision conflict") 673 674 } 675 676 func TestDBBadNumberOfRetries(t *testing.T) { 677 startCouchDB() 678 database := "testdbbadretries" 679 err := cleanup(database) 680 assert.NoError(t, err, "Error when trying to cleanup Error: %s", err) 681 defer cleanup(database) 682 683 //create a new instance and database object 684 config := testConfig() 685 config.MaxRetries = -1 686 config.MaxRetriesOnStartup = 3 687 _, err = CreateCouchInstance(config, &disabled.Provider{}) 688 assert.Error(t, err, "Error should have been thrown while attempting to create a database") 689 690 } 691 692 func TestDBBadJSON(t *testing.T) { 693 startCouchDB() 694 database := "testdbbadjson" 695 err := cleanup(database) 696 assert.NoError(t, err, "Error when trying to cleanup Error: %s", err) 697 defer cleanup(database) 698 699 //create a new instance and database object 700 couchInstance, err := CreateCouchInstance(testConfig(), &disabled.Provider{}) 701 assert.NoError(t, err, "Error when trying to create couch instance") 702 db := CouchDatabase{CouchInstance: couchInstance, DBName: database} 703 704 //create a new database 705 errdb := db.CreateDatabaseIfNotExist() 706 assert.NoError(t, errdb, "Error when trying to create database") 707 708 //Retrieve the info for the new database and make sure the name matches 709 dbResp, _, errdb := db.GetDatabaseInfo() 710 assert.NoError(t, errdb, "Error when trying to retrieve database information") 711 assert.Equal(t, database, dbResp.DbName) 712 713 badJSON := []byte(`{"asset_name"}`) 714 715 //Save the test document 716 _, saveerr := db.SaveDoc("1", "", &CouchDoc{JSONValue: badJSON, Attachments: nil}) 717 assert.Error(t, saveerr, "Error should have been thrown for a bad JSON") 718 719 } 720 721 func TestPrefixScan(t *testing.T) { 722 startCouchDB() 723 database := "testprefixscan" 724 err := cleanup(database) 725 assert.NoError(t, err, "Error when trying to cleanup Error: %s", err) 726 defer cleanup(database) 727 728 //create a new instance and database object 729 couchInstance, err := CreateCouchInstance(testConfig(), &disabled.Provider{}) 730 assert.NoError(t, err, "Error when trying to create couch instance") 731 db := CouchDatabase{CouchInstance: couchInstance, DBName: database} 732 733 //create a new database 734 errdb := db.CreateDatabaseIfNotExist() 735 assert.NoError(t, errdb, "Error when trying to create database") 736 737 //Retrieve the info for the new database and make sure the name matches 738 dbResp, _, errdb := db.GetDatabaseInfo() 739 assert.NoError(t, errdb, "Error when trying to retrieve database information") 740 assert.Equal(t, database, dbResp.DbName) 741 742 //Save documents 743 for i := 0; i < 20; i++ { 744 id1 := string(0) + string(i) + string(0) 745 id2 := string(0) + string(i) + string(1) 746 id3 := string(0) + string(i) + string(utf8.MaxRune-1) 747 _, saveerr := db.SaveDoc(id1, "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 748 assert.NoError(t, saveerr, "Error when trying to save a document") 749 _, saveerr = db.SaveDoc(id2, "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 750 assert.NoError(t, saveerr, "Error when trying to save a document") 751 _, saveerr = db.SaveDoc(id3, "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 752 assert.NoError(t, saveerr, "Error when trying to save a document") 753 754 } 755 startKey := string(0) + string(10) 756 endKey := startKey + string(utf8.MaxRune) 757 _, _, geterr := db.ReadDoc(endKey) 758 assert.NoError(t, geterr, "Error when trying to get lastkey") 759 760 resultsPtr, _, geterr := db.ReadDocRange(startKey, endKey, 1000) 761 assert.NoError(t, geterr, "Error when trying to perform a range scan") 762 assert.NotNil(t, resultsPtr) 763 results := resultsPtr 764 assert.Equal(t, 3, len(results)) 765 assert.Equal(t, string(0)+string(10)+string(0), results[0].ID) 766 assert.Equal(t, string(0)+string(10)+string(1), results[1].ID) 767 assert.Equal(t, string(0)+string(10)+string(utf8.MaxRune-1), results[2].ID) 768 769 //Drop the database 770 _, errdbdrop := db.DropDatabase() 771 assert.NoError(t, errdbdrop, "Error dropping database") 772 773 //Retrieve the info for the new database and make sure the name matches 774 _, _, errdbinfo := db.GetDatabaseInfo() 775 assert.Error(t, errdbinfo, "Error should have been thrown for missing database") 776 777 } 778 779 func TestDBSaveAttachment(t *testing.T) { 780 startCouchDB() 781 database := "testdbsaveattachment" 782 err := cleanup(database) 783 assert.NoError(t, err, "Error when trying to cleanup Error: %s", err) 784 defer cleanup(database) 785 786 byteText := []byte(`This is a test document. This is only a test`) 787 788 attachment := &AttachmentInfo{} 789 attachment.AttachmentBytes = byteText 790 attachment.ContentType = "text/plain" 791 attachment.Length = uint64(len(byteText)) 792 attachment.Name = "valueBytes" 793 794 attachments := []*AttachmentInfo{} 795 attachments = append(attachments, attachment) 796 797 //create a new instance and database object 798 couchInstance, err := CreateCouchInstance(testConfig(), &disabled.Provider{}) 799 assert.NoError(t, err, "Error when trying to create couch instance") 800 db := CouchDatabase{CouchInstance: couchInstance, DBName: database} 801 802 //create a new database 803 errdb := db.CreateDatabaseIfNotExist() 804 assert.NoError(t, errdb, "Error when trying to create database") 805 806 //Save the test document 807 _, saveerr := db.SaveDoc("10", "", &CouchDoc{JSONValue: nil, Attachments: attachments}) 808 assert.NoError(t, saveerr, "Error when trying to save a document") 809 810 //Attempt to retrieve the updated test document with attachments 811 couchDoc, _, geterr2 := db.ReadDoc("10") 812 assert.NoError(t, geterr2, "Error when trying to retrieve a document with attachment") 813 assert.NotNil(t, couchDoc.Attachments) 814 assert.Equal(t, byteText, couchDoc.Attachments[0].AttachmentBytes) 815 assert.Equal(t, attachment.Length, couchDoc.Attachments[0].Length) 816 817 } 818 819 func TestDBDeleteDocument(t *testing.T) { 820 startCouchDB() 821 database := "testdbdeletedocument" 822 err := cleanup(database) 823 assert.NoError(t, err, "Error when trying to cleanup Error: %s", err) 824 defer cleanup(database) 825 826 //create a new instance and database object 827 couchInstance, err := CreateCouchInstance(testConfig(), &disabled.Provider{}) 828 assert.NoError(t, err, "Error when trying to create couch instance") 829 db := CouchDatabase{CouchInstance: couchInstance, DBName: database} 830 831 //create a new database 832 errdb := db.CreateDatabaseIfNotExist() 833 assert.NoError(t, errdb, "Error when trying to create database") 834 835 //Save the test document 836 _, saveerr := db.SaveDoc("2", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 837 assert.NoError(t, saveerr, "Error when trying to save a document") 838 839 //Attempt to retrieve the test document 840 _, _, readErr := db.ReadDoc("2") 841 assert.NoError(t, readErr, "Error when trying to retrieve a document with attachment") 842 843 //Delete the test document 844 deleteErr := db.DeleteDoc("2", "") 845 assert.NoError(t, deleteErr, "Error when trying to delete a document") 846 847 //Attempt to retrieve the test document 848 readValue, _, _ := db.ReadDoc("2") 849 assert.Nil(t, readValue) 850 851 } 852 853 func TestDBDeleteNonExistingDocument(t *testing.T) { 854 startCouchDB() 855 database := "testdbdeletenonexistingdocument" 856 err := cleanup(database) 857 assert.NoError(t, err, "Error when trying to cleanup Error: %s", err) 858 defer cleanup(database) 859 860 //create a new instance and database object 861 couchInstance, err := CreateCouchInstance(testConfig(), &disabled.Provider{}) 862 assert.NoError(t, err, "Error when trying to create couch instance") 863 db := CouchDatabase{CouchInstance: couchInstance, DBName: database} 864 865 //create a new database 866 errdb := db.CreateDatabaseIfNotExist() 867 assert.NoError(t, errdb, "Error when trying to create database") 868 869 //Save the test document 870 deleteErr := db.DeleteDoc("2", "") 871 assert.NoError(t, deleteErr, "Error when trying to delete a non existing document") 872 } 873 874 func TestCouchDBVersion(t *testing.T) { 875 startCouchDB() 876 err := checkCouchDBVersion("2.0.0") 877 assert.NoError(t, err, "Error should not have been thrown for valid version") 878 879 err = checkCouchDBVersion("4.5.0") 880 assert.NoError(t, err, "Error should not have been thrown for valid version") 881 882 err = checkCouchDBVersion("1.6.5.4") 883 assert.Error(t, err, "Error should have been thrown for invalid version") 884 885 err = checkCouchDBVersion("0.0.0.0") 886 assert.Error(t, err, "Error should have been thrown for invalid version") 887 888 } 889 890 func TestIndexOperations(t *testing.T) { 891 startCouchDB() 892 database := "testindexoperations" 893 err := cleanup(database) 894 assert.NoError(t, err, "Error when trying to cleanup Error: %s", err) 895 defer cleanup(database) 896 897 byteJSON1 := []byte(`{"_id":"1", "asset_name":"marble1","color":"blue","size":1,"owner":"jerry"}`) 898 byteJSON2 := []byte(`{"_id":"2", "asset_name":"marble2","color":"red","size":2,"owner":"tom"}`) 899 byteJSON3 := []byte(`{"_id":"3", "asset_name":"marble3","color":"green","size":3,"owner":"jerry"}`) 900 byteJSON4 := []byte(`{"_id":"4", "asset_name":"marble4","color":"purple","size":4,"owner":"tom"}`) 901 byteJSON5 := []byte(`{"_id":"5", "asset_name":"marble5","color":"blue","size":5,"owner":"jerry"}`) 902 byteJSON6 := []byte(`{"_id":"6", "asset_name":"marble6","color":"white","size":6,"owner":"tom"}`) 903 byteJSON7 := []byte(`{"_id":"7", "asset_name":"marble7","color":"white","size":7,"owner":"tom"}`) 904 byteJSON8 := []byte(`{"_id":"8", "asset_name":"marble8","color":"white","size":8,"owner":"tom"}`) 905 byteJSON9 := []byte(`{"_id":"9", "asset_name":"marble9","color":"white","size":9,"owner":"tom"}`) 906 byteJSON10 := []byte(`{"_id":"10", "asset_name":"marble10","color":"white","size":10,"owner":"tom"}`) 907 908 //create a new instance and database object -------------------------------------------------------- 909 couchInstance, err := CreateCouchInstance(testConfig(), &disabled.Provider{}) 910 assert.NoError(t, err, "Error when trying to create couch instance") 911 db := CouchDatabase{CouchInstance: couchInstance, DBName: database} 912 913 //create a new database 914 errdb := db.CreateDatabaseIfNotExist() 915 assert.NoError(t, errdb, "Error when trying to create database") 916 917 batchUpdateDocs := []*CouchDoc{} 918 919 batchUpdateDocs = append(batchUpdateDocs, &CouchDoc{JSONValue: byteJSON1, Attachments: nil}) 920 batchUpdateDocs = append(batchUpdateDocs, &CouchDoc{JSONValue: byteJSON2, Attachments: nil}) 921 batchUpdateDocs = append(batchUpdateDocs, &CouchDoc{JSONValue: byteJSON3, Attachments: nil}) 922 batchUpdateDocs = append(batchUpdateDocs, &CouchDoc{JSONValue: byteJSON4, Attachments: nil}) 923 batchUpdateDocs = append(batchUpdateDocs, &CouchDoc{JSONValue: byteJSON5, Attachments: nil}) 924 batchUpdateDocs = append(batchUpdateDocs, &CouchDoc{JSONValue: byteJSON6, Attachments: nil}) 925 batchUpdateDocs = append(batchUpdateDocs, &CouchDoc{JSONValue: byteJSON7, Attachments: nil}) 926 batchUpdateDocs = append(batchUpdateDocs, &CouchDoc{JSONValue: byteJSON8, Attachments: nil}) 927 batchUpdateDocs = append(batchUpdateDocs, &CouchDoc{JSONValue: byteJSON9, Attachments: nil}) 928 batchUpdateDocs = append(batchUpdateDocs, &CouchDoc{JSONValue: byteJSON10, Attachments: nil}) 929 930 _, err = db.BatchUpdateDocuments(batchUpdateDocs) 931 assert.NoError(t, err, "Error adding batch of documents") 932 933 //Create an index definition 934 indexDefSize := `{"index":{"fields":[{"size":"desc"}]},"ddoc":"indexSizeSortDoc", "name":"indexSizeSortName","type":"json"}` 935 936 //Create the index 937 _, err = db.CreateIndex(indexDefSize) 938 assert.NoError(t, err, "Error thrown while creating an index") 939 940 //Retrieve the list of indexes 941 //Delay for 100ms since CouchDB index list is updated async after index create/drop 942 time.Sleep(100 * time.Millisecond) 943 listResult, err := db.ListIndex() 944 assert.NoError(t, err, "Error thrown while retrieving indexes") 945 946 //There should only be one item returned 947 assert.Equal(t, 1, len(listResult)) 948 949 //Verify the returned definition 950 for _, elem := range listResult { 951 assert.Equal(t, "indexSizeSortDoc", elem.DesignDocument) 952 assert.Equal(t, "indexSizeSortName", elem.Name) 953 //ensure the index definition is correct, CouchDB 2.1.1 will also return "partial_filter_selector":{} 954 assert.Equal(t, true, strings.Contains(elem.Definition, `"fields":[{"size":"desc"}]`)) 955 } 956 957 //Create an index definition with no DesignDocument or name 958 indexDefColor := `{"index":{"fields":[{"color":"desc"}]}}` 959 960 //Create the index 961 _, err = db.CreateIndex(indexDefColor) 962 assert.NoError(t, err, "Error thrown while creating an index") 963 964 //Retrieve the list of indexes 965 //Delay for 100ms since CouchDB index list is updated async after index create/drop 966 time.Sleep(100 * time.Millisecond) 967 listResult, err = db.ListIndex() 968 assert.NoError(t, err, "Error thrown while retrieving indexes") 969 970 //There should be two indexes returned 971 assert.Equal(t, 2, len(listResult)) 972 973 //Delete the named index 974 err = db.DeleteIndex("indexSizeSortDoc", "indexSizeSortName") 975 assert.NoError(t, err, "Error thrown while deleting an index") 976 977 //Retrieve the list of indexes 978 //Delay for 100ms since CouchDB index list is updated async after index create/drop 979 time.Sleep(100 * time.Millisecond) 980 listResult, err = db.ListIndex() 981 assert.NoError(t, err, "Error thrown while retrieving indexes") 982 983 //There should be one index returned 984 assert.Equal(t, 1, len(listResult)) 985 986 //Delete the unnamed index 987 for _, elem := range listResult { 988 err = db.DeleteIndex(elem.DesignDocument, elem.Name) 989 assert.NoError(t, err, "Error thrown while deleting an index") 990 } 991 992 //Retrieve the list of indexes 993 //Delay for 100ms since CouchDB index list is updated async after index create/drop 994 time.Sleep(100 * time.Millisecond) 995 listResult, err = db.ListIndex() 996 assert.NoError(t, err, "Error thrown while retrieving indexes") 997 assert.Equal(t, 0, len(listResult)) 998 999 //Create a query string with a descending sort, this will require an index 1000 queryString := `{"selector":{"size": {"$gt": 0}},"fields": ["_id", "_rev", "owner", "asset_name", "color", "size"], "sort":[{"size":"desc"}], "limit": 10,"skip": 0}` 1001 1002 //Execute a query with a sort, this should throw the exception 1003 _, _, err = db.QueryDocuments(queryString) 1004 assert.Error(t, err, "Error should have thrown while querying without a valid index") 1005 1006 //Create the index 1007 _, err = db.CreateIndex(indexDefSize) 1008 assert.NoError(t, err, "Error thrown while creating an index") 1009 1010 //Delay for 100ms since CouchDB index list is updated async after index create/drop 1011 time.Sleep(100 * time.Millisecond) 1012 1013 //Execute a query with an index, this should succeed 1014 _, _, err = db.QueryDocuments(queryString) 1015 assert.NoError(t, err, "Error thrown while querying with an index") 1016 1017 //Create another index definition 1018 indexDefSize = `{"index":{"fields":[{"data.size":"desc"},{"data.owner":"desc"}]},"ddoc":"indexSizeOwnerSortDoc", "name":"indexSizeOwnerSortName","type":"json"}` 1019 1020 //Create the index 1021 dbResp, err := db.CreateIndex(indexDefSize) 1022 assert.NoError(t, err, "Error thrown while creating an index") 1023 1024 //verify the response is "created" for an index creation 1025 assert.Equal(t, "created", dbResp.Result) 1026 1027 //Delay for 100ms since CouchDB index list is updated async after index create/drop 1028 time.Sleep(100 * time.Millisecond) 1029 1030 //Update the index 1031 dbResp, err = db.CreateIndex(indexDefSize) 1032 assert.NoError(t, err, "Error thrown while creating an index") 1033 1034 //verify the response is "exists" for an update 1035 assert.Equal(t, "exists", dbResp.Result) 1036 1037 //Retrieve the list of indexes 1038 //Delay for 100ms since CouchDB index list is updated async after index create/drop 1039 time.Sleep(100 * time.Millisecond) 1040 listResult, err = db.ListIndex() 1041 assert.NoError(t, err, "Error thrown while retrieving indexes") 1042 1043 //There should only be two definitions 1044 assert.Equal(t, 2, len(listResult)) 1045 1046 //Create an invalid index definition with an invalid JSON 1047 indexDefSize = `{"index"{"fields":[{"data.size":"desc"},{"data.owner":"desc"}]},"ddoc":"indexSizeOwnerSortDoc", "name":"indexSizeOwnerSortName","type":"json"}` 1048 1049 //Create the index 1050 _, err = db.CreateIndex(indexDefSize) 1051 assert.Error(t, err, "Error should have been thrown for an invalid index JSON") 1052 1053 //Create an invalid index definition with a valid JSON and an invalid index definition 1054 indexDefSize = `{"index":{"fields2":[{"data.size":"desc"},{"data.owner":"desc"}]},"ddoc":"indexSizeOwnerSortDoc", "name":"indexSizeOwnerSortName","type":"json"}` 1055 1056 //Create the index 1057 _, err = db.CreateIndex(indexDefSize) 1058 assert.Error(t, err, "Error should have been thrown for an invalid index definition") 1059 1060 } 1061 1062 func TestRichQuery(t *testing.T) { 1063 startCouchDB() 1064 byteJSON01 := []byte(`{"asset_name":"marble01","color":"blue","size":1,"owner":"jerry"}`) 1065 byteJSON02 := []byte(`{"asset_name":"marble02","color":"red","size":2,"owner":"tom"}`) 1066 byteJSON03 := []byte(`{"asset_name":"marble03","color":"green","size":3,"owner":"jerry"}`) 1067 byteJSON04 := []byte(`{"asset_name":"marble04","color":"purple","size":4,"owner":"tom"}`) 1068 byteJSON05 := []byte(`{"asset_name":"marble05","color":"blue","size":5,"owner":"jerry"}`) 1069 byteJSON06 := []byte(`{"asset_name":"marble06","color":"white","size":6,"owner":"tom"}`) 1070 byteJSON07 := []byte(`{"asset_name":"marble07","color":"white","size":7,"owner":"tom"}`) 1071 byteJSON08 := []byte(`{"asset_name":"marble08","color":"white","size":8,"owner":"tom"}`) 1072 byteJSON09 := []byte(`{"asset_name":"marble09","color":"white","size":9,"owner":"tom"}`) 1073 byteJSON10 := []byte(`{"asset_name":"marble10","color":"white","size":10,"owner":"tom"}`) 1074 byteJSON11 := []byte(`{"asset_name":"marble11","color":"green","size":11,"owner":"tom"}`) 1075 byteJSON12 := []byte(`{"asset_name":"marble12","color":"green","size":12,"owner":"frank"}`) 1076 1077 attachment1 := &AttachmentInfo{} 1078 attachment1.AttachmentBytes = []byte(`marble01 - test attachment`) 1079 attachment1.ContentType = "application/octet-stream" 1080 attachment1.Name = "data" 1081 attachments1 := []*AttachmentInfo{} 1082 attachments1 = append(attachments1, attachment1) 1083 1084 attachment2 := &AttachmentInfo{} 1085 attachment2.AttachmentBytes = []byte(`marble02 - test attachment`) 1086 attachment2.ContentType = "application/octet-stream" 1087 attachment2.Name = "data" 1088 attachments2 := []*AttachmentInfo{} 1089 attachments2 = append(attachments2, attachment2) 1090 1091 attachment3 := &AttachmentInfo{} 1092 attachment3.AttachmentBytes = []byte(`marble03 - test attachment`) 1093 attachment3.ContentType = "application/octet-stream" 1094 attachment3.Name = "data" 1095 attachments3 := []*AttachmentInfo{} 1096 attachments3 = append(attachments3, attachment3) 1097 1098 attachment4 := &AttachmentInfo{} 1099 attachment4.AttachmentBytes = []byte(`marble04 - test attachment`) 1100 attachment4.ContentType = "application/octet-stream" 1101 attachment4.Name = "data" 1102 attachments4 := []*AttachmentInfo{} 1103 attachments4 = append(attachments4, attachment4) 1104 1105 attachment5 := &AttachmentInfo{} 1106 attachment5.AttachmentBytes = []byte(`marble05 - test attachment`) 1107 attachment5.ContentType = "application/octet-stream" 1108 attachment5.Name = "data" 1109 attachments5 := []*AttachmentInfo{} 1110 attachments5 = append(attachments5, attachment5) 1111 1112 attachment6 := &AttachmentInfo{} 1113 attachment6.AttachmentBytes = []byte(`marble06 - test attachment`) 1114 attachment6.ContentType = "application/octet-stream" 1115 attachment6.Name = "data" 1116 attachments6 := []*AttachmentInfo{} 1117 attachments6 = append(attachments6, attachment6) 1118 1119 attachment7 := &AttachmentInfo{} 1120 attachment7.AttachmentBytes = []byte(`marble07 - test attachment`) 1121 attachment7.ContentType = "application/octet-stream" 1122 attachment7.Name = "data" 1123 attachments7 := []*AttachmentInfo{} 1124 attachments7 = append(attachments7, attachment7) 1125 1126 attachment8 := &AttachmentInfo{} 1127 attachment8.AttachmentBytes = []byte(`marble08 - test attachment`) 1128 attachment8.ContentType = "application/octet-stream" 1129 attachment7.Name = "data" 1130 attachments8 := []*AttachmentInfo{} 1131 attachments8 = append(attachments8, attachment8) 1132 1133 attachment9 := &AttachmentInfo{} 1134 attachment9.AttachmentBytes = []byte(`marble09 - test attachment`) 1135 attachment9.ContentType = "application/octet-stream" 1136 attachment9.Name = "data" 1137 attachments9 := []*AttachmentInfo{} 1138 attachments9 = append(attachments9, attachment9) 1139 1140 attachment10 := &AttachmentInfo{} 1141 attachment10.AttachmentBytes = []byte(`marble10 - test attachment`) 1142 attachment10.ContentType = "application/octet-stream" 1143 attachment10.Name = "data" 1144 attachments10 := []*AttachmentInfo{} 1145 attachments10 = append(attachments10, attachment10) 1146 1147 attachment11 := &AttachmentInfo{} 1148 attachment11.AttachmentBytes = []byte(`marble11 - test attachment`) 1149 attachment11.ContentType = "application/octet-stream" 1150 attachment11.Name = "data" 1151 attachments11 := []*AttachmentInfo{} 1152 attachments11 = append(attachments11, attachment11) 1153 1154 attachment12 := &AttachmentInfo{} 1155 attachment12.AttachmentBytes = []byte(`marble12 - test attachment`) 1156 attachment12.ContentType = "application/octet-stream" 1157 attachment12.Name = "data" 1158 attachments12 := []*AttachmentInfo{} 1159 attachments12 = append(attachments12, attachment12) 1160 1161 database := "testrichquery" 1162 err := cleanup(database) 1163 assert.NoError(t, err, "Error when trying to cleanup Error: %s", err) 1164 defer cleanup(database) 1165 1166 //create a new instance and database object -------------------------------------------------------- 1167 couchInstance, err := CreateCouchInstance(testConfig(), &disabled.Provider{}) 1168 assert.NoError(t, err, "Error when trying to create couch instance") 1169 db := CouchDatabase{CouchInstance: couchInstance, DBName: database} 1170 1171 //create a new database 1172 errdb := db.CreateDatabaseIfNotExist() 1173 assert.NoError(t, errdb, "Error when trying to create database") 1174 1175 //Save the test document 1176 _, saveerr := db.SaveDoc("marble01", "", &CouchDoc{JSONValue: byteJSON01, Attachments: attachments1}) 1177 assert.NoError(t, saveerr, "Error when trying to save a document") 1178 1179 //Save the test document 1180 _, saveerr = db.SaveDoc("marble02", "", &CouchDoc{JSONValue: byteJSON02, Attachments: attachments2}) 1181 assert.NoError(t, saveerr, "Error when trying to save a document") 1182 1183 //Save the test document 1184 _, saveerr = db.SaveDoc("marble03", "", &CouchDoc{JSONValue: byteJSON03, Attachments: attachments3}) 1185 assert.NoError(t, saveerr, "Error when trying to save a document") 1186 1187 //Save the test document 1188 _, saveerr = db.SaveDoc("marble04", "", &CouchDoc{JSONValue: byteJSON04, Attachments: attachments4}) 1189 assert.NoError(t, saveerr, "Error when trying to save a document") 1190 1191 //Save the test document 1192 _, saveerr = db.SaveDoc("marble05", "", &CouchDoc{JSONValue: byteJSON05, Attachments: attachments5}) 1193 assert.NoError(t, saveerr, "Error when trying to save a document") 1194 1195 //Save the test document 1196 _, saveerr = db.SaveDoc("marble06", "", &CouchDoc{JSONValue: byteJSON06, Attachments: attachments6}) 1197 assert.NoError(t, saveerr, "Error when trying to save a document") 1198 1199 //Save the test document 1200 _, saveerr = db.SaveDoc("marble07", "", &CouchDoc{JSONValue: byteJSON07, Attachments: attachments7}) 1201 assert.NoError(t, saveerr, "Error when trying to save a document") 1202 1203 //Save the test document 1204 _, saveerr = db.SaveDoc("marble08", "", &CouchDoc{JSONValue: byteJSON08, Attachments: attachments8}) 1205 assert.NoError(t, saveerr, "Error when trying to save a document") 1206 1207 //Save the test document 1208 _, saveerr = db.SaveDoc("marble09", "", &CouchDoc{JSONValue: byteJSON09, Attachments: attachments9}) 1209 assert.NoError(t, saveerr, "Error when trying to save a document") 1210 1211 //Save the test document 1212 _, saveerr = db.SaveDoc("marble10", "", &CouchDoc{JSONValue: byteJSON10, Attachments: attachments10}) 1213 assert.NoError(t, saveerr, "Error when trying to save a document") 1214 1215 //Save the test document 1216 _, saveerr = db.SaveDoc("marble11", "", &CouchDoc{JSONValue: byteJSON11, Attachments: attachments11}) 1217 assert.NoError(t, saveerr, "Error when trying to save a document") 1218 1219 //Save the test document 1220 _, saveerr = db.SaveDoc("marble12", "", &CouchDoc{JSONValue: byteJSON12, Attachments: attachments12}) 1221 assert.NoError(t, saveerr, "Error when trying to save a document") 1222 1223 //Test query with invalid JSON ------------------------------------------------------------------- 1224 queryString := `{"selector":{"owner":}}` 1225 1226 _, _, err = db.QueryDocuments(queryString) 1227 assert.Error(t, err, "Error should have been thrown for bad json") 1228 1229 //Test query with object ------------------------------------------------------------------- 1230 queryString = `{"selector":{"owner":{"$eq":"jerry"}}}` 1231 1232 queryResult, _, err := db.QueryDocuments(queryString) 1233 assert.NoError(t, err, "Error when attempting to execute a query") 1234 1235 //There should be 3 results for owner="jerry" 1236 assert.Equal(t, 3, len(queryResult)) 1237 1238 //Test query with implicit operator -------------------------------------------------------------- 1239 queryString = `{"selector":{"owner":"jerry"}}` 1240 1241 queryResult, _, err = db.QueryDocuments(queryString) 1242 assert.NoError(t, err, "Error when attempting to execute a query") 1243 1244 //There should be 3 results for owner="jerry" 1245 assert.Equal(t, 3, len(queryResult)) 1246 1247 //Test query with specified fields ------------------------------------------------------------------- 1248 queryString = `{"selector":{"owner":{"$eq":"jerry"}},"fields": ["owner","asset_name","color","size"]}` 1249 1250 queryResult, _, err = db.QueryDocuments(queryString) 1251 assert.NoError(t, err, "Error when attempting to execute a query") 1252 1253 //There should be 3 results for owner="jerry" 1254 assert.Equal(t, 3, len(queryResult)) 1255 1256 //Test query with a leading operator ------------------------------------------------------------------- 1257 queryString = `{"selector":{"$or":[{"owner":{"$eq":"jerry"}},{"owner": {"$eq": "frank"}}]}}` 1258 1259 queryResult, _, err = db.QueryDocuments(queryString) 1260 assert.NoError(t, err, "Error when attempting to execute a query") 1261 1262 //There should be 4 results for owner="jerry" or owner="frank" 1263 assert.Equal(t, 4, len(queryResult)) 1264 1265 //Test query implicit and explicit operator ------------------------------------------------------------------ 1266 queryString = `{"selector":{"color":"green","$or":[{"owner":"tom"},{"owner":"frank"}]}}` 1267 1268 queryResult, _, err = db.QueryDocuments(queryString) 1269 assert.NoError(t, err, "Error when attempting to execute a query") 1270 1271 //There should be 2 results for color="green" and (owner="jerry" or owner="frank") 1272 assert.Equal(t, 2, len(queryResult)) 1273 1274 //Test query with a leading operator ------------------------------------------------------------------------- 1275 queryString = `{"selector":{"$and":[{"size":{"$gte":2}},{"size":{"$lte":5}}]}}` 1276 1277 queryResult, _, err = db.QueryDocuments(queryString) 1278 assert.NoError(t, err, "Error when attempting to execute a query") 1279 1280 //There should be 4 results for size >= 2 and size <= 5 1281 assert.Equal(t, 4, len(queryResult)) 1282 1283 //Test query with leading and embedded operator ------------------------------------------------------------- 1284 queryString = `{"selector":{"$and":[{"size":{"$gte":3}},{"size":{"$lte":10}},{"$not":{"size":7}}]}}` 1285 1286 queryResult, _, err = db.QueryDocuments(queryString) 1287 assert.NoError(t, err, "Error when attempting to execute a query") 1288 1289 //There should be 7 results for size >= 3 and size <= 10 and not 7 1290 assert.Equal(t, 7, len(queryResult)) 1291 1292 //Test query with leading operator and array of objects ---------------------------------------------------------- 1293 queryString = `{"selector":{"$and":[{"size":{"$gte":2}},{"size":{"$lte":10}},{"$nor":[{"size":3},{"size":5},{"size":7}]}]}}` 1294 1295 queryResult, _, err = db.QueryDocuments(queryString) 1296 assert.NoError(t, err, "Error when attempting to execute a query") 1297 1298 //There should be 6 results for size >= 2 and size <= 10 and not 3,5 or 7 1299 assert.Equal(t, 6, len(queryResult)) 1300 1301 //Test a range query --------------------------------------------------------------------------------------------- 1302 queryResult, _, err = db.ReadDocRange("marble02", "marble06", 10000) 1303 assert.NoError(t, err, "Error when attempting to execute a range query") 1304 1305 //There should be 4 results 1306 assert.Equal(t, 4, len(queryResult)) 1307 1308 //Attachments retrieved should be correct 1309 assert.Equal(t, attachment2.AttachmentBytes, queryResult[0].Attachments[0].AttachmentBytes) 1310 assert.Equal(t, attachment3.AttachmentBytes, queryResult[1].Attachments[0].AttachmentBytes) 1311 assert.Equal(t, attachment4.AttachmentBytes, queryResult[2].Attachments[0].AttachmentBytes) 1312 assert.Equal(t, attachment5.AttachmentBytes, queryResult[3].Attachments[0].AttachmentBytes) 1313 1314 //Test query with for tom ------------------------------------------------------------------- 1315 queryString = `{"selector":{"owner":{"$eq":"tom"}}}` 1316 1317 queryResult, _, err = db.QueryDocuments(queryString) 1318 assert.NoError(t, err, "Error when attempting to execute a query") 1319 1320 //There should be 8 results for owner="tom" 1321 assert.Equal(t, 8, len(queryResult)) 1322 1323 //Test query with for tom with limit ------------------------------------------------------------------- 1324 queryString = `{"selector":{"owner":{"$eq":"tom"}},"limit":2}` 1325 1326 queryResult, _, err = db.QueryDocuments(queryString) 1327 assert.NoError(t, err, "Error when attempting to execute a query") 1328 1329 //There should be 2 results for owner="tom" with a limit of 2 1330 assert.Equal(t, 2, len(queryResult)) 1331 1332 //Create an index definition 1333 indexDefSize := `{"index":{"fields":[{"size":"desc"}]},"ddoc":"indexSizeSortDoc", "name":"indexSizeSortName","type":"json"}` 1334 1335 //Create the index 1336 _, err = db.CreateIndex(indexDefSize) 1337 assert.NoError(t, err, "Error thrown while creating an index") 1338 1339 //Delay for 100ms since CouchDB index list is updated async after index create/drop 1340 time.Sleep(100 * time.Millisecond) 1341 1342 //Test query with valid index ------------------------------------------------------------------- 1343 queryString = `{"selector":{"size":{"$gt":0}}, "use_index":["indexSizeSortDoc","indexSizeSortName"]}` 1344 1345 _, _, err = db.QueryDocuments(queryString) 1346 assert.NoError(t, err, "Error when attempting to execute a query with a valid index") 1347 1348 } 1349 1350 func testBatchBatchOperations(t *testing.T, maxRetries int) { 1351 1352 byteJSON01 := []byte(`{"_id":"marble01","asset_name":"marble01","color":"blue","size":"1","owner":"jerry"}`) 1353 byteJSON02 := []byte(`{"_id":"marble02","asset_name":"marble02","color":"red","size":"2","owner":"tom"}`) 1354 byteJSON03 := []byte(`{"_id":"marble03","asset_name":"marble03","color":"green","size":"3","owner":"jerry"}`) 1355 byteJSON04 := []byte(`{"_id":"marble04","asset_name":"marble04","color":"purple","size":"4","owner":"tom"}`) 1356 byteJSON05 := []byte(`{"_id":"marble05","asset_name":"marble05","color":"blue","size":"5","owner":"jerry"}`) 1357 byteJSON06 := []byte(`{"_id":"marble06#$&'()*+,/:;=?@[]","asset_name":"marble06#$&'()*+,/:;=?@[]","color":"blue","size":"6","owner":"jerry"}`) 1358 1359 attachment1 := &AttachmentInfo{} 1360 attachment1.AttachmentBytes = []byte(`marble01 - test attachment`) 1361 attachment1.ContentType = "application/octet-stream" 1362 attachment1.Name = "data" 1363 attachments1 := []*AttachmentInfo{} 1364 attachments1 = append(attachments1, attachment1) 1365 1366 attachment2 := &AttachmentInfo{} 1367 attachment2.AttachmentBytes = []byte(`marble02 - test attachment`) 1368 attachment2.ContentType = "application/octet-stream" 1369 attachment2.Name = "data" 1370 attachments2 := []*AttachmentInfo{} 1371 attachments2 = append(attachments2, attachment2) 1372 1373 attachment3 := &AttachmentInfo{} 1374 attachment3.AttachmentBytes = []byte(`marble03 - test attachment`) 1375 attachment3.ContentType = "application/octet-stream" 1376 attachment3.Name = "data" 1377 attachments3 := []*AttachmentInfo{} 1378 attachments3 = append(attachments3, attachment3) 1379 1380 attachment4 := &AttachmentInfo{} 1381 attachment4.AttachmentBytes = []byte(`marble04 - test attachment`) 1382 attachment4.ContentType = "application/octet-stream" 1383 attachment4.Name = "data" 1384 attachments4 := []*AttachmentInfo{} 1385 attachments4 = append(attachments4, attachment4) 1386 1387 attachment5 := &AttachmentInfo{} 1388 attachment5.AttachmentBytes = []byte(`marble05 - test attachment`) 1389 attachment5.ContentType = "application/octet-stream" 1390 attachment5.Name = "data" 1391 attachments5 := []*AttachmentInfo{} 1392 attachments5 = append(attachments5, attachment5) 1393 1394 attachment6 := &AttachmentInfo{} 1395 attachment6.AttachmentBytes = []byte(`marble06#$&'()*+,/:;=?@[] - test attachment`) 1396 attachment6.ContentType = "application/octet-stream" 1397 attachment6.Name = "data" 1398 attachments6 := []*AttachmentInfo{} 1399 attachments6 = append(attachments6, attachment6) 1400 1401 database := "testbatch" 1402 err := cleanup(database) 1403 assert.NoError(t, err, "Error when trying to cleanup Error: %s", err) 1404 defer cleanup(database) 1405 1406 //create a new instance and database object -------------------------------------------------------- 1407 couchInstance, err := CreateCouchInstance(testConfig(), &disabled.Provider{}) 1408 assert.NoError(t, err, "Error when trying to create couch instance") 1409 db := CouchDatabase{CouchInstance: couchInstance, DBName: database} 1410 1411 //create a new database 1412 errdb := db.CreateDatabaseIfNotExist() 1413 assert.NoError(t, errdb, "Error when trying to create database") 1414 1415 batchUpdateDocs := []*CouchDoc{} 1416 1417 value1 := &CouchDoc{JSONValue: byteJSON01, Attachments: attachments1} 1418 value2 := &CouchDoc{JSONValue: byteJSON02, Attachments: attachments2} 1419 value3 := &CouchDoc{JSONValue: byteJSON03, Attachments: attachments3} 1420 value4 := &CouchDoc{JSONValue: byteJSON04, Attachments: attachments4} 1421 value5 := &CouchDoc{JSONValue: byteJSON05, Attachments: attachments5} 1422 value6 := &CouchDoc{JSONValue: byteJSON06, Attachments: attachments6} 1423 1424 batchUpdateDocs = append(batchUpdateDocs, value1) 1425 batchUpdateDocs = append(batchUpdateDocs, value2) 1426 batchUpdateDocs = append(batchUpdateDocs, value3) 1427 batchUpdateDocs = append(batchUpdateDocs, value4) 1428 batchUpdateDocs = append(batchUpdateDocs, value5) 1429 batchUpdateDocs = append(batchUpdateDocs, value6) 1430 1431 batchUpdateResp, err := db.BatchUpdateDocuments(batchUpdateDocs) 1432 assert.NoError(t, err, "Error when attempting to update a batch of documents") 1433 1434 //check to make sure each batch update response was successful 1435 for _, updateDoc := range batchUpdateResp { 1436 assert.Equal(t, true, updateDoc.Ok) 1437 } 1438 1439 //---------------------------------------------- 1440 //Test Retrieve JSON 1441 dbGetResp, _, geterr := db.ReadDoc("marble01") 1442 assert.NoError(t, geterr, "Error when attempting read a document") 1443 1444 assetResp := &Asset{} 1445 geterr = json.Unmarshal(dbGetResp.JSONValue, &assetResp) 1446 assert.NoError(t, geterr, "Error when trying to retrieve a document") 1447 //Verify the owner retrieved matches 1448 assert.Equal(t, "jerry", assetResp.Owner) 1449 1450 //---------------------------------------------- 1451 // Test Retrieve JSON using ID with URL special characters, 1452 // this will confirm that batch document IDs and URL IDs are consistent, even if they include special characters 1453 dbGetResp, _, geterr = db.ReadDoc("marble06#$&'()*+,/:;=?@[]") 1454 assert.NoError(t, geterr, "Error when attempting read a document") 1455 1456 assetResp = &Asset{} 1457 geterr = json.Unmarshal(dbGetResp.JSONValue, &assetResp) 1458 assert.NoError(t, geterr, "Error when trying to retrieve a document") 1459 //Verify the owner retrieved matches 1460 assert.Equal(t, "jerry", assetResp.Owner) 1461 1462 //---------------------------------------------- 1463 //Test retrieve binary 1464 dbGetResp, _, geterr = db.ReadDoc("marble03") 1465 assert.NoError(t, geterr, "Error when attempting read a document") 1466 //Retrieve the attachments 1467 attachments := dbGetResp.Attachments 1468 //Only one was saved, so take the first 1469 retrievedAttachment := attachments[0] 1470 //Verify the text matches 1471 assert.Equal(t, retrievedAttachment.AttachmentBytes, attachment3.AttachmentBytes) 1472 //---------------------------------------------- 1473 //Test Bad Updates 1474 batchUpdateDocs = []*CouchDoc{} 1475 batchUpdateDocs = append(batchUpdateDocs, value1) 1476 batchUpdateDocs = append(batchUpdateDocs, value2) 1477 batchUpdateResp, err = db.BatchUpdateDocuments(batchUpdateDocs) 1478 assert.NoError(t, err, "Error when attempting to update a batch of documents") 1479 //No revision was provided, so these two updates should fail 1480 //Verify that the "Ok" field is returned as false 1481 for _, updateDoc := range batchUpdateResp { 1482 assert.Equal(t, false, updateDoc.Ok) 1483 assert.Equal(t, updateDocumentConflictError, updateDoc.Error) 1484 assert.Equal(t, updateDocumentConflictReason, updateDoc.Reason) 1485 } 1486 1487 //---------------------------------------------- 1488 //Test Batch Retrieve Keys and Update 1489 1490 var keys []string 1491 1492 keys = append(keys, "marble01") 1493 keys = append(keys, "marble03") 1494 1495 batchRevs, err := db.BatchRetrieveDocumentMetadata(keys) 1496 assert.NoError(t, err, "Error when attempting retrieve revisions") 1497 1498 batchUpdateDocs = []*CouchDoc{} 1499 1500 //iterate through the revision docs 1501 for _, revdoc := range batchRevs { 1502 if revdoc.ID == "marble01" { 1503 //update the json with the rev and add to the batch 1504 marble01Doc := addRevisionAndDeleteStatus(revdoc.Rev, byteJSON01, false) 1505 batchUpdateDocs = append(batchUpdateDocs, &CouchDoc{JSONValue: marble01Doc, Attachments: attachments1}) 1506 } 1507 1508 if revdoc.ID == "marble03" { 1509 //update the json with the rev and add to the batch 1510 marble03Doc := addRevisionAndDeleteStatus(revdoc.Rev, byteJSON03, false) 1511 batchUpdateDocs = append(batchUpdateDocs, &CouchDoc{JSONValue: marble03Doc, Attachments: attachments3}) 1512 } 1513 } 1514 1515 //Update couchdb with the batch 1516 batchUpdateResp, err = db.BatchUpdateDocuments(batchUpdateDocs) 1517 assert.NoError(t, err, "Error when attempting to update a batch of documents") 1518 //check to make sure each batch update response was successful 1519 for _, updateDoc := range batchUpdateResp { 1520 assert.Equal(t, true, updateDoc.Ok) 1521 } 1522 1523 //---------------------------------------------- 1524 //Test Batch Delete 1525 1526 keys = []string{} 1527 1528 keys = append(keys, "marble02") 1529 keys = append(keys, "marble04") 1530 1531 batchRevs, err = db.BatchRetrieveDocumentMetadata(keys) 1532 assert.NoError(t, err, "Error when attempting retrieve revisions") 1533 1534 batchUpdateDocs = []*CouchDoc{} 1535 1536 //iterate through the revision docs 1537 for _, revdoc := range batchRevs { 1538 if revdoc.ID == "marble02" { 1539 //update the json with the rev and add to the batch 1540 marble02Doc := addRevisionAndDeleteStatus(revdoc.Rev, byteJSON02, true) 1541 batchUpdateDocs = append(batchUpdateDocs, &CouchDoc{JSONValue: marble02Doc, Attachments: attachments1}) 1542 } 1543 if revdoc.ID == "marble04" { 1544 //update the json with the rev and add to the batch 1545 marble04Doc := addRevisionAndDeleteStatus(revdoc.Rev, byteJSON04, true) 1546 batchUpdateDocs = append(batchUpdateDocs, &CouchDoc{JSONValue: marble04Doc, Attachments: attachments3}) 1547 } 1548 } 1549 1550 //Update couchdb with the batch 1551 batchUpdateResp, err = db.BatchUpdateDocuments(batchUpdateDocs) 1552 assert.NoError(t, err, "Error when attempting to update a batch of documents") 1553 1554 //check to make sure each batch update response was successful 1555 for _, updateDoc := range batchUpdateResp { 1556 assert.Equal(t, true, updateDoc.Ok) 1557 } 1558 1559 //Retrieve the test document 1560 dbGetResp, _, geterr = db.ReadDoc("marble02") 1561 assert.NoError(t, geterr, "Error when trying to retrieve a document") 1562 1563 //assert the value was deleted 1564 assert.Nil(t, dbGetResp) 1565 1566 //Retrieve the test document 1567 dbGetResp, _, geterr = db.ReadDoc("marble04") 1568 assert.NoError(t, geterr, "Error when trying to retrieve a document") 1569 1570 //assert the value was deleted 1571 assert.Nil(t, dbGetResp) 1572 1573 } 1574 1575 //addRevisionAndDeleteStatus adds keys for version and chaincodeID to the JSON value 1576 func addRevisionAndDeleteStatus(revision string, value []byte, deleted bool) []byte { 1577 1578 //create a version mapping 1579 jsonMap := make(map[string]interface{}) 1580 1581 json.Unmarshal(value, &jsonMap) 1582 1583 //add the revision 1584 if revision != "" { 1585 jsonMap["_rev"] = revision 1586 } 1587 1588 //If this record is to be deleted, set the "_deleted" property to true 1589 if deleted { 1590 jsonMap["_deleted"] = true 1591 } 1592 //marshal the data to a byte array 1593 returnJSON, _ := json.Marshal(jsonMap) 1594 1595 return returnJSON 1596 1597 } 1598 1599 func TestDatabaseSecuritySettings(t *testing.T) { 1600 startCouchDB() 1601 database := "testdbsecuritysettings" 1602 err := cleanup(database) 1603 assert.NoError(t, err, "Error when trying to cleanup Error: %s", err) 1604 defer cleanup(database) 1605 1606 //create a new instance and database object -------------------------------------------------------- 1607 couchInstance, err := CreateCouchInstance(testConfig(), &disabled.Provider{}) 1608 assert.NoError(t, err, "Error when trying to create couch instance") 1609 db := CouchDatabase{CouchInstance: couchInstance, DBName: database} 1610 1611 //create a new database 1612 errdb := db.CreateDatabaseIfNotExist() 1613 assert.NoError(t, errdb, "Error when trying to create database") 1614 1615 //Create a database security object 1616 securityPermissions := &DatabaseSecurity{} 1617 securityPermissions.Admins.Names = append(securityPermissions.Admins.Names, "admin") 1618 securityPermissions.Members.Names = append(securityPermissions.Members.Names, "admin") 1619 1620 //Apply security 1621 err = db.ApplyDatabaseSecurity(securityPermissions) 1622 assert.NoError(t, err, "Error when trying to apply database security") 1623 1624 //Retrieve database security 1625 databaseSecurity, err := db.GetDatabaseSecurity() 1626 assert.NoError(t, err, "Error when retrieving database security") 1627 1628 //Verify retrieval of admins 1629 assert.Equal(t, "admin", databaseSecurity.Admins.Names[0]) 1630 1631 //Verify retrieval of members 1632 assert.Equal(t, "admin", databaseSecurity.Members.Names[0]) 1633 1634 //Create an empty database security object 1635 securityPermissions = &DatabaseSecurity{} 1636 1637 //Apply the security 1638 err = db.ApplyDatabaseSecurity(securityPermissions) 1639 assert.NoError(t, err, "Error when trying to apply database security") 1640 1641 //Retrieve database security 1642 databaseSecurity, err = db.GetDatabaseSecurity() 1643 assert.NoError(t, err, "Error when retrieving database security") 1644 1645 //Verify retrieval of admins, should be an empty array 1646 assert.Equal(t, 0, len(databaseSecurity.Admins.Names)) 1647 1648 //Verify retrieval of members, should be an empty array 1649 assert.Equal(t, 0, len(databaseSecurity.Members.Names)) 1650 1651 } 1652 1653 func TestURLWithSpecialCharacters(t *testing.T) { 1654 startCouchDB() 1655 database := "testdb+with+plus_sign" 1656 err := cleanup(database) 1657 assert.NoError(t, err, "Error when trying to cleanup Error: %s", err) 1658 defer cleanup(database) 1659 1660 // parse a contructed URL 1661 finalURL, err := url.Parse("http://127.0.0.1:5984") 1662 assert.NoError(t, err, "error thrown while parsing couchdb url") 1663 1664 // test the constructCouchDBUrl function with multiple path elements 1665 couchdbURL := constructCouchDBUrl(finalURL, database, "_index", "designdoc", "json", "indexname") 1666 assert.Equal(t, "http://127.0.0.1:5984/testdb%2Bwith%2Bplus_sign/_index/designdoc/json/indexname", couchdbURL.String()) 1667 1668 //create a new instance and database object -------------------------------------------------------- 1669 couchInstance, err := CreateCouchInstance(testConfig(), &disabled.Provider{}) 1670 assert.NoError(t, err, "Error when trying to create couch instance") 1671 db := CouchDatabase{CouchInstance: couchInstance, DBName: database} 1672 1673 //create a new database 1674 errdb := db.CreateDatabaseIfNotExist() 1675 assert.NoError(t, errdb, "Error when trying to create database") 1676 1677 dbInfo, _, errInfo := db.GetDatabaseInfo() 1678 assert.NoError(t, errInfo, "Error when trying to get database info") 1679 1680 assert.Equal(t, database, dbInfo.DbName) 1681 1682 }