github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/core/ledger/kvledger/txmgmt/txmgr/commontests/txmgr_test.go (about) 1 /* 2 Copyright IBM Corp. 2016 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 commontests 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "testing" 23 24 "os" 25 26 "github.com/hyperledger/fabric/common/ledger/testutil" 27 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version" 28 ledgertestutil "github.com/hyperledger/fabric/core/ledger/testutil" 29 "github.com/hyperledger/fabric/protos/ledger/queryresult" 30 ) 31 32 func TestMain(m *testing.M) { 33 ledgertestutil.SetupCoreYAMLConfig() 34 os.Exit(m.Run()) 35 } 36 37 func TestTxSimulatorWithNoExistingData(t *testing.T) { 38 // run the tests for each environment configured in pkg_test.go 39 for _, testEnv := range testEnvs { 40 t.Logf("Running test for TestEnv = %s", testEnv.getName()) 41 testLedgerID := "testtxsimulatorwithnoexistingdata" 42 testEnv.init(t, testLedgerID) 43 testTxSimulatorWithNoExistingData(t, testEnv) 44 testEnv.cleanup() 45 } 46 } 47 48 func testTxSimulatorWithNoExistingData(t *testing.T, env testEnv) { 49 txMgr := env.getTxMgr() 50 s, _ := txMgr.NewTxSimulator() 51 value, err := s.GetState("ns1", "key1") 52 testutil.AssertNoError(t, err, fmt.Sprintf("Error in GetState(): %s", err)) 53 testutil.AssertNil(t, value) 54 55 s.SetState("ns1", "key1", []byte("value1")) 56 s.SetState("ns1", "key2", []byte("value2")) 57 s.SetState("ns2", "key3", []byte("value3")) 58 s.SetState("ns2", "key4", []byte("value4")) 59 60 value, _ = s.GetState("ns2", "key3") 61 testutil.AssertNil(t, value) 62 } 63 64 func TestTxSimulatorWithExistingData(t *testing.T) { 65 for _, testEnv := range testEnvs { 66 t.Run(testEnv.getName(), func(t *testing.T) { 67 testLedgerID := "testtxsimulatorwithexistingdata" 68 testEnv.init(t, testLedgerID) 69 testTxSimulatorWithExistingData(t, testEnv) 70 testEnv.cleanup() 71 }) 72 } 73 } 74 75 func testTxSimulatorWithExistingData(t *testing.T, env testEnv) { 76 txMgr := env.getTxMgr() 77 txMgrHelper := newTxMgrTestHelper(t, txMgr) 78 // simulate tx1 79 s1, _ := txMgr.NewTxSimulator() 80 s1.SetState("ns1", "key1", []byte("value1")) 81 s1.SetState("ns1", "key2", []byte("value2")) 82 s1.SetState("ns2", "key3", []byte("value3")) 83 s1.SetState("ns2", "key4", []byte("value4")) 84 s1.Done() 85 // validate and commit RWset 86 txRWSet1, _ := s1.GetTxSimulationResults() 87 txMgrHelper.validateAndCommitRWSet(txRWSet1) 88 89 // simulate tx2 that make changes to existing data 90 s2, _ := txMgr.NewTxSimulator() 91 value, _ := s2.GetState("ns1", "key1") 92 testutil.AssertEquals(t, value, []byte("value1")) 93 s2.SetState("ns1", "key1", []byte("value1_1")) 94 s2.DeleteState("ns2", "key3") 95 value, _ = s2.GetState("ns1", "key1") 96 testutil.AssertEquals(t, value, []byte("value1")) 97 s2.Done() 98 // validate and commit RWset for tx2 99 txRWSet2, _ := s2.GetTxSimulationResults() 100 txMgrHelper.validateAndCommitRWSet(txRWSet2) 101 102 // simulate tx3 103 s3, _ := txMgr.NewTxSimulator() 104 value, _ = s3.GetState("ns1", "key1") 105 testutil.AssertEquals(t, value, []byte("value1_1")) 106 value, _ = s3.GetState("ns2", "key3") 107 testutil.AssertEquals(t, value, nil) 108 s3.Done() 109 110 // verify the versions of keys in persistence 111 vv, _ := env.getVDB().GetState("ns1", "key1") 112 testutil.AssertEquals(t, vv.Version, version.NewHeight(2, 0)) 113 vv, _ = env.getVDB().GetState("ns1", "key2") 114 testutil.AssertEquals(t, vv.Version, version.NewHeight(1, 0)) 115 } 116 117 func TestTxValidation(t *testing.T) { 118 for _, testEnv := range testEnvs { 119 t.Logf("Running test for TestEnv = %s", testEnv.getName()) 120 testLedgerID := "testtxvalidation" 121 testEnv.init(t, testLedgerID) 122 testTxValidation(t, testEnv) 123 testEnv.cleanup() 124 } 125 } 126 127 func testTxValidation(t *testing.T, env testEnv) { 128 txMgr := env.getTxMgr() 129 txMgrHelper := newTxMgrTestHelper(t, txMgr) 130 // simulate tx1 131 s1, _ := txMgr.NewTxSimulator() 132 s1.SetState("ns1", "key1", []byte("value1")) 133 s1.SetState("ns1", "key2", []byte("value2")) 134 s1.SetState("ns2", "key3", []byte("value3")) 135 s1.SetState("ns2", "key4", []byte("value4")) 136 s1.Done() 137 // validate and commit RWset 138 txRWSet1, _ := s1.GetTxSimulationResults() 139 txMgrHelper.validateAndCommitRWSet(txRWSet1) 140 141 // simulate tx2 that make changes to existing data. 142 // tx2: Read/Update ns1:key1, Delete ns2:key3. 143 s2, _ := txMgr.NewTxSimulator() 144 value, _ := s2.GetState("ns1", "key1") 145 testutil.AssertEquals(t, value, []byte("value1")) 146 147 s2.SetState("ns1", "key1", []byte("value1_2")) 148 s2.DeleteState("ns2", "key3") 149 s2.Done() 150 151 // simulate tx3 before committing tx2 changes. Reads and modifies the key changed by tx2. 152 // tx3: Read/Update ns1:key1 153 s3, _ := txMgr.NewTxSimulator() 154 s3.GetState("ns1", "key1") 155 s3.SetState("ns1", "key1", []byte("value1_3")) 156 s3.Done() 157 158 // simulate tx4 before committing tx2 changes. Reads and Deletes the key changed by tx2 159 // tx4: Read/Delete ns2:key3 160 s4, _ := txMgr.NewTxSimulator() 161 s4.GetState("ns2", "key3") 162 s4.DeleteState("ns2", "key3") 163 s4.Done() 164 165 // simulate tx5 before committing tx2 changes. Modifies and then Reads the key changed by tx2 and writes a new key 166 // tx5: Update/Read ns1:key1 167 s5, _ := txMgr.NewTxSimulator() 168 s5.SetState("ns1", "key1", []byte("new_value")) 169 s5.GetState("ns1", "key1") 170 s5.Done() 171 172 // simulate tx6 before committing tx2 changes. Only writes a new key, does not reads/writes a key changed by tx2 173 // tx6: Update ns1:new_key 174 s6, _ := txMgr.NewTxSimulator() 175 s6.SetState("ns1", "new_key", []byte("new_value")) 176 s6.Done() 177 178 // Summary of simulated transactions 179 // tx2: Read/Update ns1:key1, Delete ns2:key3. 180 // tx3: Read/Update ns1:key1 181 // tx4: Read/Delete ns2:key3 182 // tx5: Update/Read ns1:key1 183 // tx6: Update ns1:new_key 184 185 // validate and commit RWset for tx2 186 txRWSet2, _ := s2.GetTxSimulationResults() 187 txMgrHelper.validateAndCommitRWSet(txRWSet2) 188 189 //RWSet for tx3 and tx4 and tx5 should be invalid now due to read conflicts 190 txRWSet3, _ := s3.GetTxSimulationResults() 191 txMgrHelper.checkRWsetInvalid(txRWSet3) 192 193 txRWSet4, _ := s4.GetTxSimulationResults() 194 txMgrHelper.checkRWsetInvalid(txRWSet4) 195 196 txRWSet5, _ := s5.GetTxSimulationResults() 197 txMgrHelper.checkRWsetInvalid(txRWSet5) 198 199 // tx6 should still be valid as it only writes a new key 200 txRWSet6, _ := s6.GetTxSimulationResults() 201 txMgrHelper.validateAndCommitRWSet(txRWSet6) 202 } 203 204 func TestTxPhantomValidation(t *testing.T) { 205 for _, testEnv := range testEnvs { 206 t.Logf("Running test for TestEnv = %s", testEnv.getName()) 207 testLedgerID := "testtxphantomvalidation" 208 testEnv.init(t, testLedgerID) 209 testTxPhantomValidation(t, testEnv) 210 testEnv.cleanup() 211 } 212 } 213 214 func testTxPhantomValidation(t *testing.T, env testEnv) { 215 txMgr := env.getTxMgr() 216 txMgrHelper := newTxMgrTestHelper(t, txMgr) 217 // simulate tx1 218 s1, _ := txMgr.NewTxSimulator() 219 s1.SetState("ns", "key1", []byte("value1")) 220 s1.SetState("ns", "key2", []byte("value2")) 221 s1.SetState("ns", "key3", []byte("value3")) 222 s1.SetState("ns", "key4", []byte("value4")) 223 s1.SetState("ns", "key5", []byte("value5")) 224 s1.SetState("ns", "key6", []byte("value6")) 225 s1.Done() 226 // validate and commit RWset 227 txRWSet1, _ := s1.GetTxSimulationResults() 228 txMgrHelper.validateAndCommitRWSet(txRWSet1) 229 230 // simulate tx2 231 s2, _ := txMgr.NewTxSimulator() 232 itr2, _ := s2.GetStateRangeScanIterator("ns", "key2", "key5") 233 for { 234 if result, _ := itr2.Next(); result == nil { 235 break 236 } 237 } 238 s2.DeleteState("ns", "key3") 239 s2.Done() 240 txRWSet2, _ := s2.GetTxSimulationResults() 241 242 // simulate tx3 243 s3, _ := txMgr.NewTxSimulator() 244 itr3, _ := s3.GetStateRangeScanIterator("ns", "key2", "key5") 245 for { 246 if result, _ := itr3.Next(); result == nil { 247 break 248 } 249 } 250 s3.SetState("ns", "key3", []byte("value3_new")) 251 s3.Done() 252 txRWSet3, _ := s3.GetTxSimulationResults() 253 254 // simulate tx4 255 s4, _ := txMgr.NewTxSimulator() 256 itr4, _ := s4.GetStateRangeScanIterator("ns", "key4", "key6") 257 for { 258 if result, _ := itr4.Next(); result == nil { 259 break 260 } 261 } 262 s4.SetState("ns", "key3", []byte("value3_new")) 263 s4.Done() 264 txRWSet4, _ := s4.GetTxSimulationResults() 265 266 // txRWSet2 should be valid 267 txMgrHelper.validateAndCommitRWSet(txRWSet2) 268 // txRWSet2 makes txRWSet3 invalid as it deletes a key in the range 269 txMgrHelper.checkRWsetInvalid(txRWSet3) 270 // txRWSet4 should be valid as it iterates over a different range 271 txMgrHelper.validateAndCommitRWSet(txRWSet4) 272 } 273 274 func TestIterator(t *testing.T) { 275 for _, testEnv := range testEnvs { 276 t.Logf("Running test for TestEnv = %s", testEnv.getName()) 277 278 testLedgerID := "testiterator_1" 279 testEnv.init(t, testLedgerID) 280 testIterator(t, testEnv, 10, 2, 7) 281 testEnv.cleanup() 282 283 testLedgerID = "testiterator_2" 284 testEnv.init(t, testLedgerID) 285 testIterator(t, testEnv, 10, 1, 11) 286 testEnv.cleanup() 287 288 testLedgerID = "testiterator_3" 289 testEnv.init(t, testLedgerID) 290 testIterator(t, testEnv, 10, 0, 0) 291 testEnv.cleanup() 292 293 testLedgerID = "testiterator_4" 294 testEnv.init(t, testLedgerID) 295 testIterator(t, testEnv, 10, 5, 0) 296 testEnv.cleanup() 297 298 testLedgerID = "testiterator_5" 299 testEnv.init(t, testLedgerID) 300 testIterator(t, testEnv, 10, 0, 5) 301 testEnv.cleanup() 302 } 303 } 304 305 func testIterator(t *testing.T, env testEnv, numKeys int, startKeyNum int, endKeyNum int) { 306 cID := "cID" 307 txMgr := env.getTxMgr() 308 txMgrHelper := newTxMgrTestHelper(t, txMgr) 309 s, _ := txMgr.NewTxSimulator() 310 for i := 1; i <= numKeys; i++ { 311 k := createTestKey(i) 312 v := createTestValue(i) 313 t.Logf("Adding k=[%s], v=[%s]", k, v) 314 s.SetState(cID, k, v) 315 } 316 s.Done() 317 // validate and commit RWset 318 txRWSet, _ := s.GetTxSimulationResults() 319 txMgrHelper.validateAndCommitRWSet(txRWSet) 320 321 var startKey string 322 var endKey string 323 var begin int 324 var end int 325 326 if startKeyNum != 0 { 327 begin = startKeyNum 328 startKey = createTestKey(startKeyNum) 329 } else { 330 begin = 1 //first key in the db 331 startKey = "" 332 } 333 334 if endKeyNum != 0 { 335 endKey = createTestKey(endKeyNum) 336 end = endKeyNum 337 } else { 338 endKey = "" 339 end = numKeys + 1 //last key in the db 340 } 341 342 expectedCount := end - begin 343 344 queryExecuter, _ := txMgr.NewQueryExecutor() 345 itr, _ := queryExecuter.GetStateRangeScanIterator(cID, startKey, endKey) 346 count := 0 347 for { 348 kv, _ := itr.Next() 349 if kv == nil { 350 break 351 } 352 keyNum := begin + count 353 k := kv.(*queryresult.KV).Key 354 v := kv.(*queryresult.KV).Value 355 t.Logf("Retrieved k=%s, v=%s at count=%d start=%s end=%s", k, v, count, startKey, endKey) 356 testutil.AssertEquals(t, k, createTestKey(keyNum)) 357 testutil.AssertEquals(t, v, createTestValue(keyNum)) 358 count++ 359 } 360 testutil.AssertEquals(t, count, expectedCount) 361 } 362 363 func TestIteratorWithDeletes(t *testing.T) { 364 for _, testEnv := range testEnvs { 365 t.Logf("Running test for TestEnv = %s", testEnv.getName()) 366 testLedgerID := "testiteratorwithdeletes" 367 testEnv.init(t, testLedgerID) 368 testIteratorWithDeletes(t, testEnv) 369 testEnv.cleanup() 370 } 371 } 372 373 func testIteratorWithDeletes(t *testing.T, env testEnv) { 374 cID := "cID" 375 txMgr := env.getTxMgr() 376 txMgrHelper := newTxMgrTestHelper(t, txMgr) 377 s, _ := txMgr.NewTxSimulator() 378 for i := 1; i <= 10; i++ { 379 k := createTestKey(i) 380 v := createTestValue(i) 381 t.Logf("Adding k=[%s], v=[%s]", k, v) 382 s.SetState(cID, k, v) 383 } 384 s.Done() 385 // validate and commit RWset 386 txRWSet1, _ := s.GetTxSimulationResults() 387 txMgrHelper.validateAndCommitRWSet(txRWSet1) 388 389 s, _ = txMgr.NewTxSimulator() 390 s.DeleteState(cID, createTestKey(4)) 391 s.Done() 392 // validate and commit RWset 393 txRWSet2, _ := s.GetTxSimulationResults() 394 txMgrHelper.validateAndCommitRWSet(txRWSet2) 395 396 queryExecuter, _ := txMgr.NewQueryExecutor() 397 itr, _ := queryExecuter.GetStateRangeScanIterator(cID, createTestKey(3), createTestKey(6)) 398 defer itr.Close() 399 kv, _ := itr.Next() 400 testutil.AssertEquals(t, kv.(*queryresult.KV).Key, createTestKey(3)) 401 kv, _ = itr.Next() 402 testutil.AssertEquals(t, kv.(*queryresult.KV).Key, createTestKey(5)) 403 } 404 405 func TestTxValidationWithItr(t *testing.T) { 406 for _, testEnv := range testEnvs { 407 t.Logf("Running test for TestEnv = %s", testEnv.getName()) 408 testLedgerID := "testtxvalidationwithitr" 409 testEnv.init(t, testLedgerID) 410 testTxValidationWithItr(t, testEnv) 411 testEnv.cleanup() 412 } 413 } 414 415 func testTxValidationWithItr(t *testing.T, env testEnv) { 416 cID := "cID" 417 txMgr := env.getTxMgr() 418 txMgrHelper := newTxMgrTestHelper(t, txMgr) 419 420 // simulate tx1 421 s1, _ := txMgr.NewTxSimulator() 422 for i := 1; i <= 10; i++ { 423 k := createTestKey(i) 424 v := createTestValue(i) 425 t.Logf("Adding k=[%s], v=[%s]", k, v) 426 s1.SetState(cID, k, v) 427 } 428 s1.Done() 429 // validate and commit RWset 430 txRWSet1, _ := s1.GetTxSimulationResults() 431 txMgrHelper.validateAndCommitRWSet(txRWSet1) 432 433 // simulate tx2 that reads key_001 and key_002 434 s2, _ := txMgr.NewTxSimulator() 435 itr, _ := s2.GetStateRangeScanIterator(cID, createTestKey(1), createTestKey(5)) 436 // read key_001 and key_002 437 itr.Next() 438 itr.Next() 439 itr.Close() 440 s2.Done() 441 442 // simulate tx3 that reads key_004 and key_005 443 s3, _ := txMgr.NewTxSimulator() 444 itr, _ = s3.GetStateRangeScanIterator(cID, createTestKey(4), createTestKey(6)) 445 // read key_001 and key_002 446 itr.Next() 447 itr.Next() 448 itr.Close() 449 s3.Done() 450 451 // simulate tx4 before committing tx2 and tx3. Modifies a key read by tx3 452 s4, _ := txMgr.NewTxSimulator() 453 s4.DeleteState(cID, createTestKey(5)) 454 s4.Done() 455 456 // validate and commit RWset for tx4 457 txRWSet4, _ := s4.GetTxSimulationResults() 458 txMgrHelper.validateAndCommitRWSet(txRWSet4) 459 460 //RWSet tx3 should be invalid now 461 txRWSet3, _ := s3.GetTxSimulationResults() 462 txMgrHelper.checkRWsetInvalid(txRWSet3) 463 464 // tx2 should still be valid 465 txRWSet2, _ := s2.GetTxSimulationResults() 466 txMgrHelper.validateAndCommitRWSet(txRWSet2) 467 468 } 469 470 func TestGetSetMultipeKeys(t *testing.T) { 471 for _, testEnv := range testEnvs { 472 t.Logf("Running test for TestEnv = %s", testEnv.getName()) 473 testLedgerID := "testgetsetmultipekeys" 474 testEnv.init(t, testLedgerID) 475 testGetSetMultipeKeys(t, testEnv) 476 testEnv.cleanup() 477 } 478 } 479 480 func testGetSetMultipeKeys(t *testing.T, env testEnv) { 481 cID := "cID" 482 txMgr := env.getTxMgr() 483 txMgrHelper := newTxMgrTestHelper(t, txMgr) 484 // simulate tx1 485 s1, _ := txMgr.NewTxSimulator() 486 multipleKeyMap := make(map[string][]byte) 487 for i := 1; i <= 10; i++ { 488 k := createTestKey(i) 489 v := createTestValue(i) 490 multipleKeyMap[k] = v 491 } 492 s1.SetStateMultipleKeys(cID, multipleKeyMap) 493 s1.Done() 494 // validate and commit RWset 495 txRWSet, _ := s1.GetTxSimulationResults() 496 txMgrHelper.validateAndCommitRWSet(txRWSet) 497 qe, _ := txMgr.NewQueryExecutor() 498 defer qe.Done() 499 multipleKeys := []string{} 500 for k := range multipleKeyMap { 501 multipleKeys = append(multipleKeys, k) 502 } 503 values, _ := qe.GetStateMultipleKeys(cID, multipleKeys) 504 testutil.AssertEquals(t, len(values), 10) 505 for i, v := range values { 506 testutil.AssertEquals(t, v, multipleKeyMap[multipleKeys[i]]) 507 } 508 509 s2, _ := txMgr.NewTxSimulator() 510 defer s2.Done() 511 values, _ = s2.GetStateMultipleKeys(cID, multipleKeys[5:7]) 512 testutil.AssertEquals(t, len(values), 2) 513 for i, v := range values { 514 testutil.AssertEquals(t, v, multipleKeyMap[multipleKeys[i+5]]) 515 } 516 } 517 518 func createTestKey(i int) string { 519 if i == 0 { 520 return "" 521 } 522 return fmt.Sprintf("key_%03d", i) 523 } 524 525 func createTestValue(i int) []byte { 526 return []byte(fmt.Sprintf("value_%03d", i)) 527 } 528 529 //TestExecuteQueryQuery is only tested on the CouchDB testEnv 530 func TestExecuteQuery(t *testing.T) { 531 532 for _, testEnv := range testEnvs { 533 // Query is only supported and tested on the CouchDB testEnv 534 if testEnv.getName() == couchDBtestEnvName { 535 t.Logf("Running test for TestEnv = %s", testEnv.getName()) 536 testLedgerID := "testexecutequery" 537 testEnv.init(t, testLedgerID) 538 testExecuteQuery(t, testEnv) 539 testEnv.cleanup() 540 } 541 } 542 } 543 544 func testExecuteQuery(t *testing.T, env testEnv) { 545 546 type Asset struct { 547 ID string `json:"_id"` 548 Rev string `json:"_rev"` 549 AssetName string `json:"asset_name"` 550 Color string `json:"color"` 551 Size string `json:"size"` 552 Owner string `json:"owner"` 553 } 554 555 txMgr := env.getTxMgr() 556 txMgrHelper := newTxMgrTestHelper(t, txMgr) 557 558 s1, _ := txMgr.NewTxSimulator() 559 560 s1.SetState("ns1", "key1", []byte("value1")) 561 s1.SetState("ns1", "key2", []byte("value2")) 562 s1.SetState("ns1", "key3", []byte("value3")) 563 s1.SetState("ns1", "key4", []byte("value4")) 564 s1.SetState("ns1", "key5", []byte("value5")) 565 s1.SetState("ns1", "key6", []byte("value6")) 566 s1.SetState("ns1", "key7", []byte("value7")) 567 s1.SetState("ns1", "key8", []byte("value8")) 568 569 s1.SetState("ns1", "key9", []byte(`{"asset_name":"marble1","color":"red","size":"25","owner":"jerry"}`)) 570 s1.SetState("ns1", "key10", []byte(`{"asset_name":"marble2","color":"blue","size":"10","owner":"bob"}`)) 571 s1.SetState("ns1", "key11", []byte(`{"asset_name":"marble3","color":"blue","size":"35","owner":"jerry"}`)) 572 s1.SetState("ns1", "key12", []byte(`{"asset_name":"marble4","color":"green","size":"15","owner":"bob"}`)) 573 s1.SetState("ns1", "key13", []byte(`{"asset_name":"marble5","color":"red","size":"35","owner":"jerry"}`)) 574 s1.SetState("ns1", "key14", []byte(`{"asset_name":"marble6","color":"blue","size":"25","owner":"bob"}`)) 575 576 s1.Done() 577 578 // validate and commit RWset 579 txRWSet, _ := s1.GetTxSimulationResults() 580 txMgrHelper.validateAndCommitRWSet(txRWSet) 581 582 queryExecuter, _ := txMgr.NewQueryExecutor() 583 queryString := "{\"selector\":{\"owner\": {\"$eq\": \"bob\"}},\"limit\": 10,\"skip\": 0}" 584 585 itr, err := queryExecuter.ExecuteQuery("ns1", queryString) 586 testutil.AssertNoError(t, err, "Error upon ExecuteQuery()") 587 588 counter := 0 589 for { 590 queryRecord, _ := itr.Next() 591 if queryRecord == nil { 592 break 593 } 594 595 //Unmarshal the document to Asset structure 596 assetResp := &Asset{} 597 json.Unmarshal(queryRecord.(*queryresult.KV).Value, &assetResp) 598 599 //Verify the owner retrieved matches 600 testutil.AssertEquals(t, assetResp.Owner, "bob") 601 602 counter++ 603 604 } 605 606 //Ensure the query returns 3 documents 607 testutil.AssertEquals(t, counter, 3) 608 609 }