github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/core/ledger/util/couchdb/couchdb_test.go (about) 1 /* 2 Copyright IBM Corp. 2016, 2017 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package couchdb 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "os" 23 "strings" 24 "testing" 25 "time" 26 "unicode/utf8" 27 28 "github.com/hyperledger/fabric/common/ledger/testutil" 29 "github.com/hyperledger/fabric/core/ledger/ledgerconfig" 30 ledgertestutil "github.com/hyperledger/fabric/core/ledger/testutil" 31 "github.com/spf13/viper" 32 ) 33 34 const badConnectURL = "couchdb:5990" 35 const updateDocumentConflictError = "conflict" 36 const updateDocumentConflictReason = "Document update conflict." 37 38 var couchDBDef *CouchDBDef 39 40 func cleanup(database string) error { 41 //create a new connection 42 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 43 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 44 45 if err != nil { 46 fmt.Println("Unexpected error", err) 47 return err 48 } 49 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 50 //drop the test database 51 db.DropDatabase() 52 return nil 53 } 54 55 type Asset struct { 56 ID string `json:"_id"` 57 Rev string `json:"_rev"` 58 AssetName string `json:"asset_name"` 59 Color string `json:"color"` 60 Size string `json:"size"` 61 Owner string `json:"owner"` 62 } 63 64 var assetJSON = []byte(`{"asset_name":"marble1","color":"blue","size":"35","owner":"jerry"}`) 65 66 func TestMain(m *testing.M) { 67 // Read the core.yaml file for default config. 68 ledgertestutil.SetupCoreYAMLConfig() 69 70 // Switch to CouchDB 71 viper.Set("ledger.state.stateDatabase", "CouchDB") 72 73 // both vagrant and CI have couchdb configured at host "couchdb" 74 viper.Set("ledger.state.couchDBConfig.couchDBAddress", "couchdb:5984") 75 // Replace with correct username/password such as 76 // admin/admin if user security is enabled on couchdb. 77 viper.Set("ledger.state.couchDBConfig.username", "") 78 viper.Set("ledger.state.couchDBConfig.password", "") 79 viper.Set("ledger.state.couchDBConfig.maxRetries", 3) 80 viper.Set("ledger.state.couchDBConfig.maxRetriesOnStartup", 10) 81 viper.Set("ledger.state.couchDBConfig.requestTimeout", time.Second*35) 82 83 // Create CouchDB definition from config parameters 84 couchDBDef = GetCouchDBDefinition() 85 86 //run the tests 87 result := m.Run() 88 89 //revert to default goleveldb 90 viper.Set("ledger.state.stateDatabase", "goleveldb") 91 os.Exit(result) 92 } 93 94 func TestDBConnectionDef(t *testing.T) { 95 96 //create a new connection 97 _, err := CreateConnectionDefinition(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 98 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 99 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create database connection definition")) 100 101 } 102 103 func TestDBBadConnectionDef(t *testing.T) { 104 105 //create a new connection 106 _, err := CreateConnectionDefinition("^^^localhost:5984", couchDBDef.Username, couchDBDef.Password, 107 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 108 testutil.AssertError(t, err, fmt.Sprintf("Did not receive error when trying to create database connection definition with a bad hostname")) 109 110 } 111 112 func TestDBCreateSaveWithoutRevision(t *testing.T) { 113 114 if ledgerconfig.IsCouchDBEnabled() { 115 116 database := "testdbcreatesavewithoutrevision" 117 err := cleanup(database) 118 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 119 defer cleanup(database) 120 121 if err == nil { 122 //create a new instance and database object 123 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 124 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 125 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 126 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 127 128 //create a new database 129 _, errdb := db.CreateDatabaseIfNotExist() 130 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database")) 131 132 //Save the test document 133 _, saveerr := db.SaveDoc("2", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 134 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 135 } 136 } 137 } 138 139 func TestDBCreateEnsureFullCommit(t *testing.T) { 140 141 if ledgerconfig.IsCouchDBEnabled() { 142 143 database := "testdbensurefullcommit" 144 err := cleanup(database) 145 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 146 defer cleanup(database) 147 148 if err == nil { 149 //create a new instance and database object 150 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 151 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 152 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 153 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 154 155 //create a new database 156 _, errdb := db.CreateDatabaseIfNotExist() 157 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database")) 158 159 //Save the test document 160 _, saveerr := db.SaveDoc("2", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 161 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 162 163 //Ensure a full commit 164 _, commiterr := db.EnsureFullCommit() 165 testutil.AssertNoError(t, commiterr, fmt.Sprintf("Error when trying to ensure a full commit")) 166 167 } 168 } 169 } 170 171 func TestDBBadDatabaseName(t *testing.T) { 172 173 if ledgerconfig.IsCouchDBEnabled() { 174 175 //create a new instance and database object using a valid database name mixed case 176 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 177 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 178 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 179 _, dberr := CreateCouchDatabase(*couchInstance, "testDB") 180 testutil.AssertNoError(t, dberr, fmt.Sprintf("Error when testing a valid database name")) 181 182 //create a new instance and database object using a valid database name letters and numbers 183 couchInstance, err = CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 184 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 185 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 186 _, dberr = CreateCouchDatabase(*couchInstance, "test132") 187 testutil.AssertNoError(t, dberr, fmt.Sprintf("Error when testing a valid database name")) 188 189 //create a new instance and database object using a valid database name - special characters 190 couchInstance, err = CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 191 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 192 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 193 _, dberr = CreateCouchDatabase(*couchInstance, "test1234~!@#$%^&*()[]{}.") 194 testutil.AssertNoError(t, dberr, fmt.Sprintf("Error when testing a valid database name")) 195 196 //create a new instance and database object using a invalid database name - too long /* 197 couchInstance, err = CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 198 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 199 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 200 _, dberr = CreateCouchDatabase(*couchInstance, "A12345678901234567890123456789012345678901234"+ 201 "56789012345678901234567890123456789012345678901234567890123456789012345678901234567890"+ 202 "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456"+ 203 "78901234567890123456789012345678901234567890") 204 testutil.AssertError(t, dberr, fmt.Sprintf("Error should have been thrown for invalid database name")) 205 206 } 207 208 } 209 210 func TestDBBadConnection(t *testing.T) { 211 212 if ledgerconfig.IsCouchDBEnabled() { 213 214 //create a new instance and database object 215 //Limit the maxRetriesOnStartup to 3 in order to reduce time for the failure 216 _, err := CreateCouchInstance(badConnectURL, couchDBDef.Username, couchDBDef.Password, 217 couchDBDef.MaxRetries, 3, couchDBDef.RequestTimeout) 218 testutil.AssertError(t, err, fmt.Sprintf("Error should have been thrown for a bad connection")) 219 } 220 } 221 222 func TestDBCreateDatabaseAndPersist(t *testing.T) { 223 224 if ledgerconfig.IsCouchDBEnabled() { 225 226 database := "testdbcreatedatabaseandpersist" 227 err := cleanup(database) 228 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 229 defer cleanup(database) 230 231 if err == nil { 232 //create a new instance and database object 233 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 234 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 235 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 236 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 237 238 //create a new database 239 _, errdb := db.CreateDatabaseIfNotExist() 240 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database")) 241 242 //Retrieve the info for the new database and make sure the name matches 243 dbResp, _, errdb := db.GetDatabaseInfo() 244 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to retrieve database information")) 245 testutil.AssertEquals(t, dbResp.DbName, database) 246 247 //Save the test document 248 _, saveerr := db.SaveDoc("idWith/slash", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 249 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 250 251 //Retrieve the test document 252 dbGetResp, _, geterr := db.ReadDoc("idWith/slash") 253 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document")) 254 255 //Unmarshal the document to Asset structure 256 assetResp := &Asset{} 257 geterr = json.Unmarshal(dbGetResp.JSONValue, &assetResp) 258 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document")) 259 260 //Verify the owner retrieved matches 261 testutil.AssertEquals(t, assetResp.Owner, "jerry") 262 263 //Save the test document 264 _, saveerr = db.SaveDoc("1", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 265 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 266 267 //Retrieve the test document 268 dbGetResp, _, geterr = db.ReadDoc("1") 269 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document")) 270 271 //Unmarshal the document to Asset structure 272 assetResp = &Asset{} 273 geterr = json.Unmarshal(dbGetResp.JSONValue, &assetResp) 274 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document")) 275 276 //Verify the owner retrieved matches 277 testutil.AssertEquals(t, assetResp.Owner, "jerry") 278 279 //Change owner to bob 280 assetResp.Owner = "bob" 281 282 //create a byte array of the JSON 283 assetDocUpdated, _ := json.Marshal(assetResp) 284 285 //Save the updated test document 286 _, saveerr = db.SaveDoc("1", "", &CouchDoc{JSONValue: assetDocUpdated, Attachments: nil}) 287 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save the updated document")) 288 289 //Retrieve the updated test document 290 dbGetResp, _, geterr = db.ReadDoc("1") 291 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document")) 292 293 //Unmarshal the document to Asset structure 294 assetResp = &Asset{} 295 json.Unmarshal(dbGetResp.JSONValue, &assetResp) 296 297 //Assert that the update was saved and retrieved 298 testutil.AssertEquals(t, assetResp.Owner, "bob") 299 300 //Drop the database 301 _, errdbdrop := db.DropDatabase() 302 testutil.AssertNoError(t, errdbdrop, fmt.Sprintf("Error dropping database")) 303 304 //Retrieve the info for the new database and make sure the name matches 305 _, _, errdbinfo := db.GetDatabaseInfo() 306 testutil.AssertError(t, errdbinfo, fmt.Sprintf("Error should have been thrown for missing database")) 307 } 308 } 309 310 } 311 312 func TestDBRequestTimeout(t *testing.T) { 313 314 if ledgerconfig.IsCouchDBEnabled() { 315 316 database := "testdbrequesttimeout" 317 err := cleanup(database) 318 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 319 defer cleanup(database) 320 321 if err == nil { 322 323 //create an impossibly short timeout 324 impossibleTimeout := time.Microsecond * 1 325 326 //create a new instance and database object with a timeout that will fail 327 //Also use a maxRetriesOnStartup=3 to reduce the number of retries 328 _, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 329 couchDBDef.MaxRetries, 3, impossibleTimeout) 330 testutil.AssertError(t, err, fmt.Sprintf("Error should have been thown while trying to create a couchdb instance with a connection timeout")) 331 332 //see if the error message contains the timeout error 333 testutil.AssertEquals(t, strings.Count(err.Error(), "Client.Timeout exceeded while awaiting headers"), 1) 334 335 } 336 } 337 } 338 339 func TestDBBadJSON(t *testing.T) { 340 341 if ledgerconfig.IsCouchDBEnabled() { 342 343 database := "testdbbadjson" 344 err := cleanup(database) 345 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 346 defer cleanup(database) 347 348 if err == nil { 349 350 //create a new instance and database object 351 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 352 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 353 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 354 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 355 356 //create a new database 357 _, errdb := db.CreateDatabaseIfNotExist() 358 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database")) 359 360 //Retrieve the info for the new database and make sure the name matches 361 dbResp, _, errdb := db.GetDatabaseInfo() 362 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to retrieve database information")) 363 testutil.AssertEquals(t, dbResp.DbName, database) 364 365 badJSON := []byte(`{"asset_name"}`) 366 367 //Save the test document 368 _, saveerr := db.SaveDoc("1", "", &CouchDoc{JSONValue: badJSON, Attachments: nil}) 369 testutil.AssertError(t, saveerr, fmt.Sprintf("Error should have been thrown for a bad JSON")) 370 371 } 372 373 } 374 375 } 376 377 func TestPrefixScan(t *testing.T) { 378 if !ledgerconfig.IsCouchDBEnabled() { 379 return 380 } 381 database := "testprefixscan" 382 err := cleanup(database) 383 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 384 defer cleanup(database) 385 386 if err == nil { 387 //create a new instance and database object 388 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 389 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 390 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 391 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 392 393 //create a new database 394 _, errdb := db.CreateDatabaseIfNotExist() 395 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database")) 396 397 //Retrieve the info for the new database and make sure the name matches 398 dbResp, _, errdb := db.GetDatabaseInfo() 399 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to retrieve database information")) 400 testutil.AssertEquals(t, dbResp.DbName, database) 401 402 //Save documents 403 for i := 0; i < 20; i++ { 404 id1 := string(0) + string(i) + string(0) 405 id2 := string(0) + string(i) + string(1) 406 id3 := string(0) + string(i) + string(utf8.MaxRune-1) 407 _, saveerr := db.SaveDoc(id1, "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 408 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 409 _, saveerr = db.SaveDoc(id2, "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 410 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 411 _, saveerr = db.SaveDoc(id3, "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 412 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 413 414 } 415 startKey := string(0) + string(10) 416 endKey := startKey + string(utf8.MaxRune) 417 _, _, geterr := db.ReadDoc(endKey) 418 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to get lastkey")) 419 420 resultsPtr, geterr := db.ReadDocRange(startKey, endKey, 1000, 0) 421 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to perform a range scan")) 422 testutil.AssertNotNil(t, resultsPtr) 423 results := *resultsPtr 424 testutil.AssertEquals(t, len(results), 3) 425 testutil.AssertEquals(t, results[0].ID, string(0)+string(10)+string(0)) 426 testutil.AssertEquals(t, results[1].ID, string(0)+string(10)+string(1)) 427 testutil.AssertEquals(t, results[2].ID, string(0)+string(10)+string(utf8.MaxRune-1)) 428 429 //Drop the database 430 _, errdbdrop := db.DropDatabase() 431 testutil.AssertNoError(t, errdbdrop, fmt.Sprintf("Error dropping database")) 432 433 //Retrieve the info for the new database and make sure the name matches 434 _, _, errdbinfo := db.GetDatabaseInfo() 435 testutil.AssertError(t, errdbinfo, fmt.Sprintf("Error should have been thrown for missing database")) 436 } 437 } 438 439 func TestDBSaveAttachment(t *testing.T) { 440 441 if ledgerconfig.IsCouchDBEnabled() { 442 443 database := "testdbsaveattachment" 444 err := cleanup(database) 445 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 446 defer cleanup(database) 447 448 if err == nil { 449 450 byteText := []byte(`This is a test document. This is only a test`) 451 452 attachment := &Attachment{} 453 attachment.AttachmentBytes = byteText 454 attachment.ContentType = "text/plain" 455 attachment.Name = "valueBytes" 456 457 attachments := []*Attachment{} 458 attachments = append(attachments, attachment) 459 460 //create a new instance and database object 461 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 462 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 463 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 464 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 465 466 //create a new database 467 _, errdb := db.CreateDatabaseIfNotExist() 468 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database")) 469 470 //Save the test document 471 _, saveerr := db.SaveDoc("10", "", &CouchDoc{JSONValue: nil, Attachments: attachments}) 472 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 473 474 //Attempt to retrieve the updated test document with attachments 475 couchDoc, _, geterr2 := db.ReadDoc("10") 476 testutil.AssertNoError(t, geterr2, fmt.Sprintf("Error when trying to retrieve a document with attachment")) 477 testutil.AssertNotNil(t, couchDoc.Attachments) 478 testutil.AssertEquals(t, couchDoc.Attachments[0].AttachmentBytes, byteText) 479 } 480 481 } 482 } 483 484 func TestDBDeleteDocument(t *testing.T) { 485 486 if ledgerconfig.IsCouchDBEnabled() { 487 488 database := "testdbdeletedocument" 489 err := cleanup(database) 490 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 491 defer cleanup(database) 492 493 if err == nil { 494 //create a new instance and database object 495 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 496 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 497 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 498 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 499 500 //create a new database 501 _, errdb := db.CreateDatabaseIfNotExist() 502 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database")) 503 504 //Save the test document 505 _, saveerr := db.SaveDoc("2", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil}) 506 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 507 508 //Attempt to retrieve the test document 509 _, _, readErr := db.ReadDoc("2") 510 testutil.AssertNoError(t, readErr, fmt.Sprintf("Error when trying to retrieve a document with attachment")) 511 512 //Delete the test document 513 deleteErr := db.DeleteDoc("2", "") 514 testutil.AssertNoError(t, deleteErr, fmt.Sprintf("Error when trying to delete a document")) 515 516 //Attempt to retrieve the test document 517 readValue, _, _ := db.ReadDoc("2") 518 testutil.AssertNil(t, readValue) 519 } 520 } 521 } 522 523 func TestDBDeleteNonExistingDocument(t *testing.T) { 524 525 if ledgerconfig.IsCouchDBEnabled() { 526 527 database := "testdbdeletenonexistingdocument" 528 err := cleanup(database) 529 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 530 defer cleanup(database) 531 532 if err == nil { 533 //create a new instance and database object 534 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 535 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 536 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 537 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 538 539 //create a new database 540 _, errdb := db.CreateDatabaseIfNotExist() 541 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database")) 542 543 //Save the test document 544 deleteErr := db.DeleteDoc("2", "") 545 testutil.AssertNoError(t, deleteErr, fmt.Sprintf("Error when trying to delete a non existing document")) 546 } 547 } 548 } 549 550 func TestCouchDBVersion(t *testing.T) { 551 552 err := checkCouchDBVersion("2.0.0") 553 testutil.AssertNoError(t, err, fmt.Sprintf("Error should not have been thrown for valid version")) 554 555 err = checkCouchDBVersion("4.5.0") 556 testutil.AssertNoError(t, err, fmt.Sprintf("Error should not have been thrown for valid version")) 557 558 err = checkCouchDBVersion("1.6.5.4") 559 testutil.AssertError(t, err, fmt.Sprintf("Error should have been thrown for invalid version")) 560 561 err = checkCouchDBVersion("0.0.0.0") 562 testutil.AssertError(t, err, fmt.Sprintf("Error should have been thrown for invalid version")) 563 564 } 565 566 func TestRichQuery(t *testing.T) { 567 568 if ledgerconfig.IsCouchDBEnabled() { 569 570 byteJSON01 := []byte(`{"asset_name":"marble01","color":"blue","size":1,"owner":"jerry"}`) 571 byteJSON02 := []byte(`{"asset_name":"marble02","color":"red","size":2,"owner":"tom"}`) 572 byteJSON03 := []byte(`{"asset_name":"marble03","color":"green","size":3,"owner":"jerry"}`) 573 byteJSON04 := []byte(`{"asset_name":"marble04","color":"purple","size":4,"owner":"tom"}`) 574 byteJSON05 := []byte(`{"asset_name":"marble05","color":"blue","size":5,"owner":"jerry"}`) 575 byteJSON06 := []byte(`{"asset_name":"marble06","color":"white","size":6,"owner":"tom"}`) 576 byteJSON07 := []byte(`{"asset_name":"marble07","color":"white","size":7,"owner":"tom"}`) 577 byteJSON08 := []byte(`{"asset_name":"marble08","color":"white","size":8,"owner":"tom"}`) 578 byteJSON09 := []byte(`{"asset_name":"marble09","color":"white","size":9,"owner":"tom"}`) 579 byteJSON10 := []byte(`{"asset_name":"marble10","color":"white","size":10,"owner":"tom"}`) 580 byteJSON11 := []byte(`{"asset_name":"marble11","color":"green","size":11,"owner":"tom"}`) 581 byteJSON12 := []byte(`{"asset_name":"marble12","color":"green","size":12,"owner":"frank"}`) 582 583 attachment1 := &Attachment{} 584 attachment1.AttachmentBytes = []byte(`marble01 - test attachment`) 585 attachment1.ContentType = "application/octet-stream" 586 attachment1.Name = "data" 587 attachments1 := []*Attachment{} 588 attachments1 = append(attachments1, attachment1) 589 590 attachment2 := &Attachment{} 591 attachment2.AttachmentBytes = []byte(`marble02 - test attachment`) 592 attachment2.ContentType = "application/octet-stream" 593 attachment2.Name = "data" 594 attachments2 := []*Attachment{} 595 attachments2 = append(attachments2, attachment2) 596 597 attachment3 := &Attachment{} 598 attachment3.AttachmentBytes = []byte(`marble03 - test attachment`) 599 attachment3.ContentType = "application/octet-stream" 600 attachment3.Name = "data" 601 attachments3 := []*Attachment{} 602 attachments3 = append(attachments3, attachment3) 603 604 attachment4 := &Attachment{} 605 attachment4.AttachmentBytes = []byte(`marble04 - test attachment`) 606 attachment4.ContentType = "application/octet-stream" 607 attachment4.Name = "data" 608 attachments4 := []*Attachment{} 609 attachments4 = append(attachments4, attachment4) 610 611 attachment5 := &Attachment{} 612 attachment5.AttachmentBytes = []byte(`marble05 - test attachment`) 613 attachment5.ContentType = "application/octet-stream" 614 attachment5.Name = "data" 615 attachments5 := []*Attachment{} 616 attachments5 = append(attachments5, attachment5) 617 618 attachment6 := &Attachment{} 619 attachment6.AttachmentBytes = []byte(`marble06 - test attachment`) 620 attachment6.ContentType = "application/octet-stream" 621 attachment6.Name = "data" 622 attachments6 := []*Attachment{} 623 attachments6 = append(attachments6, attachment6) 624 625 attachment7 := &Attachment{} 626 attachment7.AttachmentBytes = []byte(`marble07 - test attachment`) 627 attachment7.ContentType = "application/octet-stream" 628 attachment7.Name = "data" 629 attachments7 := []*Attachment{} 630 attachments7 = append(attachments7, attachment7) 631 632 attachment8 := &Attachment{} 633 attachment8.AttachmentBytes = []byte(`marble08 - test attachment`) 634 attachment8.ContentType = "application/octet-stream" 635 attachment7.Name = "data" 636 attachments8 := []*Attachment{} 637 attachments8 = append(attachments8, attachment8) 638 639 attachment9 := &Attachment{} 640 attachment9.AttachmentBytes = []byte(`marble09 - test attachment`) 641 attachment9.ContentType = "application/octet-stream" 642 attachment9.Name = "data" 643 attachments9 := []*Attachment{} 644 attachments9 = append(attachments9, attachment9) 645 646 attachment10 := &Attachment{} 647 attachment10.AttachmentBytes = []byte(`marble10 - test attachment`) 648 attachment10.ContentType = "application/octet-stream" 649 attachment10.Name = "data" 650 attachments10 := []*Attachment{} 651 attachments10 = append(attachments10, attachment10) 652 653 attachment11 := &Attachment{} 654 attachment11.AttachmentBytes = []byte(`marble11 - test attachment`) 655 attachment11.ContentType = "application/octet-stream" 656 attachment11.Name = "data" 657 attachments11 := []*Attachment{} 658 attachments11 = append(attachments11, attachment11) 659 660 attachment12 := &Attachment{} 661 attachment12.AttachmentBytes = []byte(`marble12 - test attachment`) 662 attachment12.ContentType = "application/octet-stream" 663 attachment12.Name = "data" 664 attachments12 := []*Attachment{} 665 attachments12 = append(attachments12, attachment12) 666 667 database := "testrichquery" 668 err := cleanup(database) 669 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 670 defer cleanup(database) 671 672 if err == nil { 673 //create a new instance and database object -------------------------------------------------------- 674 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 675 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 676 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 677 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 678 679 //create a new database 680 _, errdb := db.CreateDatabaseIfNotExist() 681 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database")) 682 683 //Save the test document 684 _, saveerr := db.SaveDoc("marble01", "", &CouchDoc{JSONValue: byteJSON01, Attachments: attachments1}) 685 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 686 687 //Save the test document 688 _, saveerr = db.SaveDoc("marble02", "", &CouchDoc{JSONValue: byteJSON02, Attachments: attachments2}) 689 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 690 691 //Save the test document 692 _, saveerr = db.SaveDoc("marble03", "", &CouchDoc{JSONValue: byteJSON03, Attachments: attachments3}) 693 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 694 695 //Save the test document 696 _, saveerr = db.SaveDoc("marble04", "", &CouchDoc{JSONValue: byteJSON04, Attachments: attachments4}) 697 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 698 699 //Save the test document 700 _, saveerr = db.SaveDoc("marble05", "", &CouchDoc{JSONValue: byteJSON05, Attachments: attachments5}) 701 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 702 703 //Save the test document 704 _, saveerr = db.SaveDoc("marble06", "", &CouchDoc{JSONValue: byteJSON06, Attachments: attachments6}) 705 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 706 707 //Save the test document 708 _, saveerr = db.SaveDoc("marble07", "", &CouchDoc{JSONValue: byteJSON07, Attachments: attachments7}) 709 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 710 711 //Save the test document 712 _, saveerr = db.SaveDoc("marble08", "", &CouchDoc{JSONValue: byteJSON08, Attachments: attachments8}) 713 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 714 715 //Save the test document 716 _, saveerr = db.SaveDoc("marble09", "", &CouchDoc{JSONValue: byteJSON09, Attachments: attachments9}) 717 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 718 719 //Save the test document 720 _, saveerr = db.SaveDoc("marble10", "", &CouchDoc{JSONValue: byteJSON10, Attachments: attachments10}) 721 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 722 723 //Save the test document 724 _, saveerr = db.SaveDoc("marble11", "", &CouchDoc{JSONValue: byteJSON11, Attachments: attachments11}) 725 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 726 727 //Save the test document 728 _, saveerr = db.SaveDoc("marble12", "", &CouchDoc{JSONValue: byteJSON12, Attachments: attachments12}) 729 testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document")) 730 731 //Test query with invalid JSON ------------------------------------------------------------------- 732 queryString := "{\"selector\":{\"owner\":}}" 733 734 _, err = db.QueryDocuments(queryString) 735 testutil.AssertError(t, err, fmt.Sprintf("Error should have been thrown for bad json")) 736 737 //Test query with object ------------------------------------------------------------------- 738 queryString = "{\"selector\":{\"owner\":{\"$eq\":\"jerry\"}}}" 739 740 queryResult, err := db.QueryDocuments(queryString) 741 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to execute a query")) 742 743 //There should be 3 results for owner="jerry" 744 testutil.AssertEquals(t, len(*queryResult), 3) 745 746 //Test query with implicit operator -------------------------------------------------------------- 747 queryString = "{\"selector\":{\"owner\":\"jerry\"}}" 748 749 queryResult, err = db.QueryDocuments(queryString) 750 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to execute a query")) 751 752 //There should be 3 results for owner="jerry" 753 testutil.AssertEquals(t, len(*queryResult), 3) 754 755 //Test query with specified fields ------------------------------------------------------------------- 756 queryString = "{\"selector\":{\"owner\":{\"$eq\":\"jerry\"}},\"fields\": [\"owner\",\"asset_name\",\"color\",\"size\"]}" 757 758 queryResult, err = db.QueryDocuments(queryString) 759 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to execute a query")) 760 761 //There should be 3 results for owner="jerry" 762 testutil.AssertEquals(t, len(*queryResult), 3) 763 764 //Test query with a leading operator ------------------------------------------------------------------- 765 queryString = "{\"selector\":{\"$or\":[{\"owner\":{\"$eq\":\"jerry\"}},{\"owner\": {\"$eq\": \"frank\"}}]}}" 766 767 queryResult, err = db.QueryDocuments(queryString) 768 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to execute a query")) 769 770 //There should be 4 results for owner="jerry" or owner="frank" 771 testutil.AssertEquals(t, len(*queryResult), 4) 772 773 //Test query implicit and explicit operator ------------------------------------------------------------------ 774 queryString = "{\"selector\":{\"color\":\"green\",\"$or\":[{\"owner\":\"tom\"},{\"owner\":\"frank\"}]}}" 775 776 queryResult, err = db.QueryDocuments(queryString) 777 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to execute a query")) 778 779 //There should be 2 results for color="green" and (owner="jerry" or owner="frank") 780 testutil.AssertEquals(t, len(*queryResult), 2) 781 782 //Test query with a leading operator ------------------------------------------------------------------------- 783 queryString = "{\"selector\":{\"$and\":[{\"size\":{\"$gte\":2}},{\"size\":{\"$lte\":5}}]}}" 784 785 queryResult, err = db.QueryDocuments(queryString) 786 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to execute a query")) 787 788 //There should be 4 results for size >= 2 and size <= 5 789 testutil.AssertEquals(t, len(*queryResult), 4) 790 791 //Test query with leading and embedded operator ------------------------------------------------------------- 792 queryString = "{\"selector\":{\"$and\":[{\"size\":{\"$gte\":3}},{\"size\":{\"$lte\":10}},{\"$not\":{\"size\":7}}]}}" 793 794 queryResult, err = db.QueryDocuments(queryString) 795 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to execute a query")) 796 797 //There should be 7 results for size >= 3 and size <= 10 and not 7 798 testutil.AssertEquals(t, len(*queryResult), 7) 799 800 //Test query with leading operator and array of objects ---------------------------------------------------------- 801 queryString = "{\"selector\":{\"$and\":[{\"size\":{\"$gte\":2}},{\"size\":{\"$lte\":10}},{\"$nor\":[{\"size\":3},{\"size\":5},{\"size\":7}]}]}}" 802 803 queryResult, err = db.QueryDocuments(queryString) 804 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to execute a query")) 805 806 //There should be 6 results for size >= 2 and size <= 10 and not 3,5 or 7 807 testutil.AssertEquals(t, len(*queryResult), 6) 808 809 //Test a range query --------------------------------------------------------------------------------------------- 810 queryResult, err = db.ReadDocRange("marble02", "marble06", 10000, 0) 811 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to execute a range query")) 812 813 //There should be 4 results 814 testutil.AssertEquals(t, len(*queryResult), 4) 815 816 //Test query with for tom ------------------------------------------------------------------- 817 queryString = "{\"selector\":{\"owner\":{\"$eq\":\"tom\"}}}" 818 819 queryResult, err = db.QueryDocuments(queryString) 820 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to execute a query")) 821 822 //There should be 8 results for owner="tom" 823 testutil.AssertEquals(t, len(*queryResult), 8) 824 825 //Test query with for tom with limit ------------------------------------------------------------------- 826 queryString = "{\"selector\":{\"owner\":{\"$eq\":\"tom\"}},\"limit\":2}" 827 828 queryResult, err = db.QueryDocuments(queryString) 829 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to execute a query")) 830 831 //There should be 2 results for owner="tom" with a limit of 2 832 testutil.AssertEquals(t, len(*queryResult), 2) 833 834 } 835 } 836 } 837 838 func TestBatchBatchOperations(t *testing.T) { 839 840 if ledgerconfig.IsCouchDBEnabled() { 841 842 byteJSON01 := []byte(`{"_id":"marble01","asset_name":"marble01","color":"blue","size":"1","owner":"jerry"}`) 843 byteJSON02 := []byte(`{"_id":"marble02","asset_name":"marble02","color":"red","size":"2","owner":"tom"}`) 844 byteJSON03 := []byte(`{"_id":"marble03","asset_name":"marble03","color":"green","size":"3","owner":"jerry"}`) 845 byteJSON04 := []byte(`{"_id":"marble04","asset_name":"marble04","color":"purple","size":"4","owner":"tom"}`) 846 byteJSON05 := []byte(`{"_id":"marble05","asset_name":"marble05","color":"blue","size":"5","owner":"jerry"}`) 847 848 attachment1 := &Attachment{} 849 attachment1.AttachmentBytes = []byte(`marble01 - test attachment`) 850 attachment1.ContentType = "application/octet-stream" 851 attachment1.Name = "data" 852 attachments1 := []*Attachment{} 853 attachments1 = append(attachments1, attachment1) 854 855 attachment2 := &Attachment{} 856 attachment2.AttachmentBytes = []byte(`marble02 - test attachment`) 857 attachment2.ContentType = "application/octet-stream" 858 attachment2.Name = "data" 859 attachments2 := []*Attachment{} 860 attachments2 = append(attachments2, attachment2) 861 862 attachment3 := &Attachment{} 863 attachment3.AttachmentBytes = []byte(`marble03 - test attachment`) 864 attachment3.ContentType = "application/octet-stream" 865 attachment3.Name = "data" 866 attachments3 := []*Attachment{} 867 attachments3 = append(attachments3, attachment3) 868 869 attachment4 := &Attachment{} 870 attachment4.AttachmentBytes = []byte(`marble04 - test attachment`) 871 attachment4.ContentType = "application/octet-stream" 872 attachment4.Name = "data" 873 attachments4 := []*Attachment{} 874 attachments4 = append(attachments4, attachment4) 875 876 attachment5 := &Attachment{} 877 attachment5.AttachmentBytes = []byte(`marble05 - test attachment`) 878 attachment5.ContentType = "application/octet-stream" 879 attachment5.Name = "data" 880 attachments5 := []*Attachment{} 881 attachments5 = append(attachments5, attachment5) 882 883 database := "testbatch" 884 err := cleanup(database) 885 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err)) 886 defer cleanup(database) 887 888 //create a new instance and database object -------------------------------------------------------- 889 couchInstance, err := CreateCouchInstance(couchDBDef.URL, couchDBDef.Username, couchDBDef.Password, 890 couchDBDef.MaxRetries, couchDBDef.MaxRetriesOnStartup, couchDBDef.RequestTimeout) 891 testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance")) 892 db := CouchDatabase{CouchInstance: *couchInstance, DBName: database} 893 894 //create a new database 895 _, errdb := db.CreateDatabaseIfNotExist() 896 testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database")) 897 898 batchUpdateDocs := []*CouchDoc{} 899 900 value1 := &CouchDoc{JSONValue: byteJSON01, Attachments: attachments1} 901 value2 := &CouchDoc{JSONValue: byteJSON02, Attachments: attachments2} 902 value3 := &CouchDoc{JSONValue: byteJSON03, Attachments: attachments3} 903 value4 := &CouchDoc{JSONValue: byteJSON04, Attachments: attachments4} 904 value5 := &CouchDoc{JSONValue: byteJSON05, Attachments: attachments5} 905 906 batchUpdateDocs = append(batchUpdateDocs, value1) 907 batchUpdateDocs = append(batchUpdateDocs, value2) 908 batchUpdateDocs = append(batchUpdateDocs, value3) 909 batchUpdateDocs = append(batchUpdateDocs, value4) 910 batchUpdateDocs = append(batchUpdateDocs, value5) 911 912 batchUpdateResp, err := db.BatchUpdateDocuments(batchUpdateDocs) 913 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to update a batch of documents")) 914 915 //check to make sure each batch update response was successful 916 for _, updateDoc := range batchUpdateResp { 917 testutil.AssertEquals(t, updateDoc.Ok, true) 918 } 919 920 //---------------------------------------------- 921 //Test Retrieve JSON 922 dbGetResp, _, geterr := db.ReadDoc("marble01") 923 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when attempting read a document")) 924 925 assetResp := &Asset{} 926 geterr = json.Unmarshal(dbGetResp.JSONValue, &assetResp) 927 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document")) 928 //Verify the owner retrieved matches 929 testutil.AssertEquals(t, assetResp.Owner, "jerry") 930 931 //---------------------------------------------- 932 //Test retrieve binary 933 dbGetResp, _, geterr = db.ReadDoc("marble03") 934 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when attempting read a document")) 935 //Retrieve the attachments 936 attachments := dbGetResp.Attachments 937 //Only one was saved, so take the first 938 retrievedAttachment := attachments[0] 939 //Verify the text matches 940 testutil.AssertEquals(t, attachment3.AttachmentBytes, retrievedAttachment.AttachmentBytes) 941 //---------------------------------------------- 942 //Test Bad Updates 943 batchUpdateDocs = []*CouchDoc{} 944 batchUpdateDocs = append(batchUpdateDocs, value1) 945 batchUpdateDocs = append(batchUpdateDocs, value2) 946 batchUpdateResp, err = db.BatchUpdateDocuments(batchUpdateDocs) 947 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to update a batch of documents")) 948 //No revision was provided, so these two updates should fail 949 //Verify that the "Ok" field is returned as false 950 for _, updateDoc := range batchUpdateResp { 951 testutil.AssertEquals(t, updateDoc.Ok, false) 952 testutil.AssertEquals(t, updateDoc.Error, updateDocumentConflictError) 953 testutil.AssertEquals(t, updateDoc.Reason, updateDocumentConflictReason) 954 } 955 956 //---------------------------------------------- 957 //Test Batch Retrieve Keys and Update 958 959 var keys []string 960 961 keys = append(keys, "marble01") 962 keys = append(keys, "marble03") 963 964 batchRevs, err := db.BatchRetrieveIDRevision(keys) 965 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting retrieve revisions")) 966 967 batchUpdateDocs = []*CouchDoc{} 968 969 //iterate through the revision docs 970 for _, revdoc := range batchRevs { 971 if revdoc.ID == "marble01" { 972 //update the json with the rev and add to the batch 973 marble01Doc := addRevisionAndDeleteStatus(revdoc.Rev, byteJSON01, false) 974 batchUpdateDocs = append(batchUpdateDocs, &CouchDoc{JSONValue: marble01Doc, Attachments: attachments1}) 975 } 976 977 if revdoc.ID == "marble03" { 978 //update the json with the rev and add to the batch 979 marble03Doc := addRevisionAndDeleteStatus(revdoc.Rev, byteJSON03, false) 980 batchUpdateDocs = append(batchUpdateDocs, &CouchDoc{JSONValue: marble03Doc, Attachments: attachments3}) 981 } 982 } 983 984 //Update couchdb with the batch 985 batchUpdateResp, err = db.BatchUpdateDocuments(batchUpdateDocs) 986 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to update a batch of documents")) 987 //check to make sure each batch update response was successful 988 for _, updateDoc := range batchUpdateResp { 989 testutil.AssertEquals(t, updateDoc.Ok, true) 990 } 991 992 //---------------------------------------------- 993 //Test Batch Delete 994 995 keys = []string{} 996 997 keys = append(keys, "marble02") 998 keys = append(keys, "marble04") 999 1000 batchRevs, err = db.BatchRetrieveIDRevision(keys) 1001 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting retrieve revisions")) 1002 1003 batchUpdateDocs = []*CouchDoc{} 1004 1005 //iterate through the revision docs 1006 for _, revdoc := range batchRevs { 1007 if revdoc.ID == "marble02" { 1008 //update the json with the rev and add to the batch 1009 marble02Doc := addRevisionAndDeleteStatus(revdoc.Rev, byteJSON02, true) 1010 batchUpdateDocs = append(batchUpdateDocs, &CouchDoc{JSONValue: marble02Doc, Attachments: attachments1}) 1011 } 1012 if revdoc.ID == "marble04" { 1013 //update the json with the rev and add to the batch 1014 marble04Doc := addRevisionAndDeleteStatus(revdoc.Rev, byteJSON04, true) 1015 batchUpdateDocs = append(batchUpdateDocs, &CouchDoc{JSONValue: marble04Doc, Attachments: attachments3}) 1016 } 1017 } 1018 1019 //Update couchdb with the batch 1020 batchUpdateResp, err = db.BatchUpdateDocuments(batchUpdateDocs) 1021 testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to update a batch of documents")) 1022 1023 //check to make sure each batch update response was successful 1024 for _, updateDoc := range batchUpdateResp { 1025 testutil.AssertEquals(t, updateDoc.Ok, true) 1026 } 1027 1028 //Retrieve the test document 1029 dbGetResp, _, geterr = db.ReadDoc("marble02") 1030 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document")) 1031 1032 //assert the value was deleted 1033 testutil.AssertNil(t, dbGetResp) 1034 1035 //Retrieve the test document 1036 dbGetResp, _, geterr = db.ReadDoc("marble04") 1037 testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document")) 1038 1039 //assert the value was deleted 1040 testutil.AssertNil(t, dbGetResp) 1041 } 1042 } 1043 1044 //addRevisionAndDeleteStatus adds keys for version and chaincodeID to the JSON value 1045 func addRevisionAndDeleteStatus(revision string, value []byte, deleted bool) []byte { 1046 1047 //create a version mapping 1048 jsonMap := make(map[string]interface{}) 1049 1050 json.Unmarshal(value, &jsonMap) 1051 1052 //add the revision 1053 if revision != "" { 1054 jsonMap["_rev"] = revision 1055 } 1056 1057 //If this record is to be deleted, set the "_deleted" property to true 1058 if deleted { 1059 jsonMap["_deleted"] = true 1060 } 1061 //marshal the data to a byte array 1062 returnJSON, _ := json.Marshal(jsonMap) 1063 1064 return returnJSON 1065 1066 }