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