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