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