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