github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/internal/peer/chaincode/common_test.go (about) 1 /* 2 Copyright Digital Asset Holdings, LLC. All Rights Reserved. 3 Copyright hechain. All Rights Reserved. 4 5 SPDX-License-Identifier: Apache-2.0 6 */ 7 8 package chaincode 9 10 import ( 11 "context" 12 "crypto/tls" 13 "encoding/json" 14 "errors" 15 "fmt" 16 "sort" 17 "testing" 18 "time" 19 20 "github.com/golang/protobuf/proto" 21 "github.com/hechain20/hechain/bccsp/sw" 22 "github.com/hechain20/hechain/common/policydsl" 23 "github.com/hechain20/hechain/core/config/configtest" 24 "github.com/hechain20/hechain/internal/peer/chaincode/mock" 25 "github.com/hechain20/hechain/internal/peer/common" 26 "github.com/hechain20/hechain/internal/pkg/identity" 27 cb "github.com/hyperledger/fabric-protos-go/common" 28 pb "github.com/hyperledger/fabric-protos-go/peer" 29 . "github.com/onsi/gomega" 30 "github.com/spf13/cobra" 31 "github.com/spf13/viper" 32 "github.com/stretchr/testify/require" 33 ) 34 35 //go:generate counterfeiter -o mock/signer_serializer.go --fake-name SignerSerializer . signerSerializer 36 37 type signerSerializer interface { 38 identity.SignerSerializer 39 } 40 41 //go:generate counterfeiter -o mock/deliver.go --fake-name Deliver . deliver 42 43 type deliver interface { 44 pb.Deliver_DeliverClient 45 } 46 47 //go:generate counterfeiter -o mock/deliver_client.go --fake-name PeerDeliverClient . peerDeliverClient 48 49 type peerDeliverClient interface { 50 pb.DeliverClient 51 } 52 53 func TestCheckChaincodeCmdParamsWithNewCallingSchema(t *testing.T) { 54 chaincodeCtorJSON = `{ "Args":["func", "param"] }` 55 chaincodePath = "some/path" 56 chaincodeName = "somename" 57 require := require.New(t) 58 result := checkChaincodeCmdParams(&cobra.Command{}) 59 60 require.Nil(result) 61 } 62 63 func TestCheckChaincodeCmdParamsWithOldCallingSchema(t *testing.T) { 64 chaincodeCtorJSON = `{ "Function":"func", "Args":["param"] }` 65 chaincodePath = "some/path" 66 chaincodeName = "somename" 67 require := require.New(t) 68 result := checkChaincodeCmdParams(&cobra.Command{}) 69 70 require.Nil(result) 71 } 72 73 func TestCheckChaincodeCmdParamsWithoutName(t *testing.T) { 74 chaincodeCtorJSON = `{ "Function":"func", "Args":["param"] }` 75 chaincodePath = "some/path" 76 chaincodeName = "" 77 require := require.New(t) 78 result := checkChaincodeCmdParams(&cobra.Command{}) 79 80 require.Error(result) 81 } 82 83 func TestCheckChaincodeCmdParamsWithFunctionOnly(t *testing.T) { 84 chaincodeCtorJSON = `{ "Function":"func" }` 85 chaincodePath = "some/path" 86 chaincodeName = "somename" 87 require := require.New(t) 88 result := checkChaincodeCmdParams(&cobra.Command{}) 89 90 require.Error(result) 91 } 92 93 func TestCheckChaincodeCmdParamsEmptyCtor(t *testing.T) { 94 chaincodeCtorJSON = `{}` 95 chaincodePath = "some/path" 96 chaincodeName = "somename" 97 require := require.New(t) 98 result := checkChaincodeCmdParams(&cobra.Command{}) 99 100 require.Error(result) 101 } 102 103 func TestCheckValidJSON(t *testing.T) { 104 validJSON := `{"Args":["a","b","c"]}` 105 input := &chaincodeInput{} 106 if err := json.Unmarshal([]byte(validJSON), &input); err != nil { 107 t.Fail() 108 t.Logf("Chaincode argument error: %s", err) 109 return 110 } 111 112 validJSON = `{"Function":"f", "Args":["a","b","c"]}` 113 if err := json.Unmarshal([]byte(validJSON), &input); err != nil { 114 t.Fail() 115 t.Logf("Chaincode argument error: %s", err) 116 return 117 } 118 119 validJSON = `{"Function":"f", "Args":[]}` 120 if err := json.Unmarshal([]byte(validJSON), &input); err != nil { 121 t.Fail() 122 t.Logf("Chaincode argument error: %s", err) 123 return 124 } 125 126 validJSON = `{"Function":"f"}` 127 if err := json.Unmarshal([]byte(validJSON), &input); err != nil { 128 t.Fail() 129 t.Logf("Chaincode argument error: %s", err) 130 return 131 } 132 } 133 134 func TestCheckInvalidJSON(t *testing.T) { 135 invalidJSON := `{["a","b","c"]}` 136 input := &chaincodeInput{} 137 if err := json.Unmarshal([]byte(invalidJSON), &input); err == nil { 138 t.Fail() 139 t.Logf("Bar argument error should have been caught: %s", invalidJSON) 140 return 141 } 142 143 invalidJSON = `{"Function":}` 144 if err := json.Unmarshal([]byte(invalidJSON), &input); err == nil { 145 t.Fail() 146 t.Logf("Chaincode argument error: %s", err) 147 t.Logf("Bar argument error should have been caught: %s", invalidJSON) 148 return 149 } 150 } 151 152 const sampleCollectionConfigGood = `[ 153 { 154 "name": "foo", 155 "policy": "OR('A.member', 'B.member')", 156 "requiredPeerCount": 3, 157 "maxPeerCount": 483279847, 158 "blockToLive":10, 159 "memberOnlyRead": true, 160 "memberOnlyWrite": true 161 } 162 ]` 163 164 const sampleCollectionConfigGoodNoMaxPeerCountOrRequiredPeerCount = `[ 165 { 166 "name": "foo", 167 "policy": "OR('A.member', 'B.member')", 168 "blockToLive":10, 169 "memberOnlyRead": true, 170 "memberOnlyWrite": true 171 } 172 ]` 173 174 const sampleCollectionConfigGoodWithSignaturePolicy = `[ 175 { 176 "name": "foo", 177 "policy": "OR('A.member', 'B.member')", 178 "requiredPeerCount": 3, 179 "maxPeerCount": 483279847, 180 "blockToLive":10, 181 "memberOnlyRead": true, 182 "memberOnlyWrite": true, 183 "endorsementPolicy": { 184 "signaturePolicy": "OR('A.member', 'B.member')" 185 } 186 } 187 ]` 188 189 const sampleCollectionConfigGoodWithChannelConfigPolicy = `[ 190 { 191 "name": "foo", 192 "policy": "OR('A.member', 'B.member')", 193 "requiredPeerCount": 3, 194 "maxPeerCount": 483279847, 195 "blockToLive":10, 196 "memberOnlyRead": true, 197 "memberOnlyWrite": true, 198 "endorsementPolicy": { 199 "channelConfigPolicy": "/Channel/Application/Endorsement" 200 } 201 } 202 ]` 203 204 const sampleCollectionConfigBad = `[ 205 { 206 "name": "foo", 207 "policy": "barf", 208 "requiredPeerCount": 3, 209 "maxPeerCount": 483279847 210 } 211 ]` 212 213 const sampleCollectionConfigBadInvalidSignaturePolicy = `[ 214 { 215 "name": "foo", 216 "policy": "OR('A.member', 'B.member')", 217 "requiredPeerCount": 3, 218 "maxPeerCount": 483279847, 219 "blockToLive":10, 220 "memberOnlyRead": true, 221 "memberOnlyWrite": true, 222 "endorsementPolicy": { 223 "signaturePolicy": "invalid" 224 } 225 } 226 ]` 227 228 const sampleCollectionConfigBadSignaturePolicyAndChannelConfigPolicy = `[ 229 { 230 "name": "foo", 231 "policy": "OR('A.member', 'B.member')", 232 "requiredPeerCount": 3, 233 "maxPeerCount": 483279847, 234 "blockToLive":10, 235 "memberOnlyRead": true, 236 "memberOnlyWrite": true, 237 "endorsementPolicy": { 238 "signaturePolicy": "OR('A.member', 'B.member')", 239 "channelConfigPolicy": "/Channel/Application/Endorsement" 240 } 241 } 242 ]` 243 244 func TestCollectionParsing(t *testing.T) { 245 ccp, ccpBytes, err := getCollectionConfigFromBytes([]byte(sampleCollectionConfigGood)) 246 require.NoError(t, err) 247 require.NotNil(t, ccp) 248 require.NotNil(t, ccpBytes) 249 conf := ccp.Config[0].GetStaticCollectionConfig() 250 pol, _ := policydsl.FromString("OR('A.member', 'B.member')") 251 require.Equal(t, 3, int(conf.RequiredPeerCount)) 252 require.Equal(t, 483279847, int(conf.MaximumPeerCount)) 253 require.Equal(t, "foo", conf.Name) 254 require.True(t, proto.Equal(pol, conf.MemberOrgsPolicy.GetSignaturePolicy())) 255 require.Equal(t, 10, int(conf.BlockToLive)) 256 require.Equal(t, true, conf.MemberOnlyRead) 257 require.Nil(t, conf.EndorsementPolicy) 258 t.Logf("conf=%s", conf) 259 260 // Test default values for RequiredPeerCount and MaxPeerCount 261 ccp, ccpBytes, err = getCollectionConfigFromBytes([]byte(sampleCollectionConfigGoodNoMaxPeerCountOrRequiredPeerCount)) 262 require.NoError(t, err) 263 require.NotNil(t, ccp) 264 require.NotNil(t, ccpBytes) 265 conf = ccp.Config[0].GetStaticCollectionConfig() 266 pol, _ = policydsl.FromString("OR('A.member', 'B.member')") 267 require.Equal(t, 0, int(conf.RequiredPeerCount)) 268 require.Equal(t, 1, int(conf.MaximumPeerCount)) 269 require.Equal(t, "foo", conf.Name) 270 require.True(t, proto.Equal(pol, conf.MemberOrgsPolicy.GetSignaturePolicy())) 271 require.Equal(t, 10, int(conf.BlockToLive)) 272 require.Equal(t, true, conf.MemberOnlyRead) 273 require.Nil(t, conf.EndorsementPolicy) 274 t.Logf("conf=%s", conf) 275 276 ccp, ccpBytes, err = getCollectionConfigFromBytes([]byte(sampleCollectionConfigGoodWithSignaturePolicy)) 277 require.NoError(t, err) 278 require.NotNil(t, ccp) 279 require.NotNil(t, ccpBytes) 280 conf = ccp.Config[0].GetStaticCollectionConfig() 281 pol, _ = policydsl.FromString("OR('A.member', 'B.member')") 282 require.Equal(t, 3, int(conf.RequiredPeerCount)) 283 require.Equal(t, 483279847, int(conf.MaximumPeerCount)) 284 require.Equal(t, "foo", conf.Name) 285 require.True(t, proto.Equal(pol, conf.MemberOrgsPolicy.GetSignaturePolicy())) 286 require.Equal(t, 10, int(conf.BlockToLive)) 287 require.Equal(t, true, conf.MemberOnlyRead) 288 require.True(t, proto.Equal(pol, conf.EndorsementPolicy.GetSignaturePolicy())) 289 t.Logf("conf=%s", conf) 290 291 ccp, ccpBytes, err = getCollectionConfigFromBytes([]byte(sampleCollectionConfigGoodWithChannelConfigPolicy)) 292 require.NoError(t, err) 293 require.NotNil(t, ccp) 294 require.NotNil(t, ccpBytes) 295 conf = ccp.Config[0].GetStaticCollectionConfig() 296 pol, _ = policydsl.FromString("OR('A.member', 'B.member')") 297 require.Equal(t, 3, int(conf.RequiredPeerCount)) 298 require.Equal(t, 483279847, int(conf.MaximumPeerCount)) 299 require.Equal(t, "foo", conf.Name) 300 require.True(t, proto.Equal(pol, conf.MemberOrgsPolicy.GetSignaturePolicy())) 301 require.Equal(t, 10, int(conf.BlockToLive)) 302 require.Equal(t, true, conf.MemberOnlyRead) 303 require.Equal(t, "/Channel/Application/Endorsement", conf.EndorsementPolicy.GetChannelConfigPolicyReference()) 304 t.Logf("conf=%s", conf) 305 306 failureTests := []struct { 307 name string 308 collectionConfig string 309 expectedErr string 310 }{ 311 { 312 name: "Invalid member orgs policy", 313 collectionConfig: sampleCollectionConfigBad, 314 expectedErr: "invalid policy barf: unrecognized token 'barf' in policy string", 315 }, 316 { 317 name: "Invalid collection config", 318 collectionConfig: "barf", 319 expectedErr: "could not parse the collection configuration: invalid character 'b' looking for beginning of value", 320 }, 321 { 322 name: "Invalid signature policy", 323 collectionConfig: sampleCollectionConfigBadInvalidSignaturePolicy, 324 expectedErr: `invalid endorsement policy [&chaincode.endorsementPolicy{ChannelConfigPolicy:"", SignaturePolicy:"invalid"}]: invalid signature policy: invalid`, 325 }, 326 { 327 name: "Signature policy and channel config policy both specified", 328 collectionConfig: sampleCollectionConfigBadSignaturePolicyAndChannelConfigPolicy, 329 expectedErr: `invalid endorsement policy [&chaincode.endorsementPolicy{ChannelConfigPolicy:"/Channel/Application/Endorsement", SignaturePolicy:"OR('A.member', 'B.member')"}]: cannot specify both "--signature-policy" and "--channel-config-policy"`, 330 }, 331 } 332 333 for _, test := range failureTests { 334 t.Run(test.name, func(t *testing.T) { 335 ccp, ccpBytes, err = getCollectionConfigFromBytes([]byte(test.collectionConfig)) 336 require.EqualError(t, err, test.expectedErr) 337 require.Nil(t, ccp) 338 require.Nil(t, ccpBytes) 339 }) 340 } 341 } 342 343 func TestValidatePeerConnectionParams(t *testing.T) { 344 defer resetFlags() 345 defer viper.Reset() 346 require := require.New(t) 347 cleanup := configtest.SetDevFabricConfigPath(t) 348 defer cleanup() 349 350 // TLS disabled 351 viper.Set("peer.tls.enabled", false) 352 353 // failure - more than one peer and TLS root cert - not invoke 354 resetFlags() 355 peerAddresses = []string{"peer0", "peer1"} 356 tlsRootCertFiles = []string{"cert0", "cert1"} 357 err := validatePeerConnectionParameters("query") 358 require.Error(err) 359 require.Contains(err.Error(), "command can only be executed against one peer") 360 361 // success - peer provided and no TLS root certs 362 // TLS disabled 363 resetFlags() 364 peerAddresses = []string{"peer0"} 365 err = validatePeerConnectionParameters("query") 366 require.NoError(err) 367 require.Nil(tlsRootCertFiles) 368 369 // success - more TLS root certs than peers 370 // TLS disabled 371 resetFlags() 372 peerAddresses = []string{"peer0"} 373 tlsRootCertFiles = []string{"cert0", "cert1"} 374 err = validatePeerConnectionParameters("invoke") 375 require.NoError(err) 376 require.Nil(tlsRootCertFiles) 377 378 // success - multiple peers and no TLS root certs - invoke 379 // TLS disabled 380 resetFlags() 381 peerAddresses = []string{"peer0", "peer1"} 382 err = validatePeerConnectionParameters("invoke") 383 require.NoError(err) 384 require.Nil(tlsRootCertFiles) 385 386 // TLS enabled 387 viper.Set("peer.tls.enabled", true) 388 389 // failure - uneven number of peers and TLS root certs - invoke 390 // TLS enabled 391 resetFlags() 392 peerAddresses = []string{"peer0", "peer1"} 393 tlsRootCertFiles = []string{"cert0"} 394 err = validatePeerConnectionParameters("invoke") 395 require.Error(err) 396 require.Contains(err.Error(), fmt.Sprintf("number of peer addresses (%d) does not match the number of TLS root cert files (%d)", len(peerAddresses), len(tlsRootCertFiles))) 397 398 // success - more than one peer and TLS root certs - invoke 399 // TLS enabled 400 resetFlags() 401 peerAddresses = []string{"peer0", "peer1"} 402 tlsRootCertFiles = []string{"cert0", "cert1"} 403 err = validatePeerConnectionParameters("invoke") 404 require.NoError(err) 405 406 // failure - connection profile doesn't exist 407 resetFlags() 408 connectionProfile = "blah" 409 err = validatePeerConnectionParameters("invoke") 410 require.Error(err) 411 require.Contains(err.Error(), "error reading connection profile") 412 413 // failure - connection profile has peer defined in channel config but 414 // not in peer config 415 resetFlags() 416 channelID = "mychannel" 417 connectionProfile = "testdata/connectionprofile-uneven.yaml" 418 err = validatePeerConnectionParameters("invoke") 419 require.Error(err) 420 require.Contains(err.Error(), "defined in the channel config but doesn't have associated peer config") 421 422 // success - connection profile exists 423 resetFlags() 424 channelID = "mychannel" 425 connectionProfile = "testdata/connectionprofile.yaml" 426 err = validatePeerConnectionParameters("invoke") 427 require.NoError(err) 428 } 429 430 func TestInitCmdFactoryFailures(t *testing.T) { 431 defer resetFlags() 432 require := require.New(t) 433 434 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 435 require.Nil(err) 436 437 // failure validating peer connection parameters 438 resetFlags() 439 peerAddresses = []string{"peer0", "peer1"} 440 tlsRootCertFiles = []string{"cert0", "cert1"} 441 cf, err := InitCmdFactory("query", true, false, cryptoProvider) 442 require.Error(err) 443 require.Contains(err.Error(), "error validating peer connection parameters: 'query' command can only be executed against one peer") 444 require.Nil(cf) 445 446 // failure - no peers supplied and endorser client is needed 447 resetFlags() 448 peerAddresses = []string{} 449 cf, err = InitCmdFactory("query", true, false, cryptoProvider) 450 require.Error(err) 451 require.Contains(err.Error(), "no endorser clients retrieved") 452 require.Nil(cf) 453 454 // failure - orderer client is needed, ordering endpoint is empty and no 455 // endorser client supplied 456 resetFlags() 457 peerAddresses = nil 458 cf, err = InitCmdFactory("invoke", false, true, cryptoProvider) 459 require.Error(err) 460 require.Contains(err.Error(), "no ordering endpoint or endorser client supplied") 461 require.Nil(cf) 462 } 463 464 func TestDeliverGroupConnect(t *testing.T) { 465 defer resetFlags() 466 g := NewGomegaWithT(t) 467 468 // success 469 mockDeliverClients := []*DeliverClient{ 470 { 471 Client: getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_VALID, "txid0"), 472 Address: "peer0", 473 }, 474 { 475 Client: getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_VALID, "txid0"), 476 Address: "peer1", 477 }, 478 } 479 dg := DeliverGroup{ 480 Clients: mockDeliverClients, 481 ChannelID: "testchannel", 482 Signer: &mock.SignerSerializer{}, 483 Certificate: tls.Certificate{ 484 Certificate: [][]byte{[]byte("test")}, 485 }, 486 TxID: "txid0", 487 } 488 err := dg.Connect(context.Background()) 489 g.Expect(err).To(BeNil()) 490 491 // failure - DeliverFiltered returns error 492 mockDC := &mock.PeerDeliverClient{} 493 mockDC.DeliverFilteredReturns(nil, errors.New("icecream")) 494 mockDeliverClients = []*DeliverClient{ 495 { 496 Client: mockDC, 497 Address: "peer0", 498 }, 499 } 500 dg = DeliverGroup{ 501 Clients: mockDeliverClients, 502 ChannelID: "testchannel", 503 Signer: &mock.SignerSerializer{}, 504 Certificate: tls.Certificate{ 505 Certificate: [][]byte{[]byte("test")}, 506 }, 507 TxID: "txid0", 508 } 509 err = dg.Connect(context.Background()) 510 g.Expect(err.Error()).To(ContainSubstring("error connecting to deliver filtered")) 511 g.Expect(err.Error()).To(ContainSubstring("icecream")) 512 513 // failure - Send returns error 514 mockD := &mock.Deliver{} 515 mockD.SendReturns(errors.New("blah")) 516 mockDC.DeliverFilteredReturns(mockD, nil) 517 mockDeliverClients = []*DeliverClient{ 518 { 519 Client: mockDC, 520 Address: "peer0", 521 }, 522 } 523 dg = DeliverGroup{ 524 Clients: mockDeliverClients, 525 ChannelID: "testchannel", 526 Signer: &mock.SignerSerializer{}, 527 Certificate: tls.Certificate{ 528 Certificate: [][]byte{[]byte("test")}, 529 }, 530 TxID: "txid0", 531 } 532 err = dg.Connect(context.Background()) 533 g.Expect(err.Error()).To(ContainSubstring("error sending deliver seek info")) 534 g.Expect(err.Error()).To(ContainSubstring("blah")) 535 536 // failure - deliver registration timeout 537 delayChan := make(chan struct{}) 538 mockDCDelay := getMockDeliverClientRegisterAfterDelay(delayChan) 539 mockDeliverClients = []*DeliverClient{ 540 { 541 Client: mockDCDelay, 542 Address: "peer0", 543 }, 544 } 545 ctx, cancelFunc := context.WithTimeout(context.Background(), 10*time.Millisecond) 546 defer cancelFunc() 547 dg = DeliverGroup{ 548 Clients: mockDeliverClients, 549 ChannelID: "testchannel", 550 Signer: &mock.SignerSerializer{}, 551 Certificate: tls.Certificate{ 552 Certificate: [][]byte{[]byte("test")}, 553 }, 554 TxID: "txid0", 555 } 556 err = dg.Connect(ctx) 557 g.Expect(err.Error()).To(ContainSubstring("timed out waiting for connection to deliver on all peers")) 558 close(delayChan) 559 } 560 561 func TestDeliverGroupWait(t *testing.T) { 562 defer resetFlags() 563 g := NewGomegaWithT(t) 564 565 // success 566 mockConn := &mock.Deliver{} 567 filteredResp := &pb.DeliverResponse{ 568 Type: &pb.DeliverResponse_FilteredBlock{FilteredBlock: createFilteredBlock(pb.TxValidationCode_VALID, "txid0")}, 569 } 570 mockConn.RecvReturns(filteredResp, nil) 571 mockDeliverClients := []*DeliverClient{ 572 { 573 Connection: mockConn, 574 Address: "peer0", 575 }, 576 } 577 dg := DeliverGroup{ 578 Clients: mockDeliverClients, 579 ChannelID: "testchannel", 580 Signer: &mock.SignerSerializer{}, 581 Certificate: tls.Certificate{ 582 Certificate: [][]byte{[]byte("test")}, 583 }, 584 TxID: "txid0", 585 } 586 err := dg.Wait(context.Background()) 587 g.Expect(err).To(BeNil()) 588 589 // failure - Recv returns error 590 mockConn = &mock.Deliver{} 591 mockConn.RecvReturns(nil, errors.New("avocado")) 592 mockDeliverClients = []*DeliverClient{ 593 { 594 Connection: mockConn, 595 Address: "peer0", 596 }, 597 } 598 dg = DeliverGroup{ 599 Clients: mockDeliverClients, 600 ChannelID: "testchannel", 601 Signer: &mock.SignerSerializer{}, 602 Certificate: tls.Certificate{ 603 Certificate: [][]byte{[]byte("test")}, 604 }, 605 TxID: "txid0", 606 } 607 err = dg.Wait(context.Background()) 608 g.Expect(err.Error()).To(ContainSubstring("error receiving from deliver filtered")) 609 g.Expect(err.Error()).To(ContainSubstring("avocado")) 610 611 // failure - Recv returns unexpected type 612 mockConn = &mock.Deliver{} 613 resp := &pb.DeliverResponse{ 614 Type: &pb.DeliverResponse_Block{}, 615 } 616 mockConn.RecvReturns(resp, nil) 617 mockDeliverClients = []*DeliverClient{ 618 { 619 Connection: mockConn, 620 Address: "peer0", 621 }, 622 } 623 dg = DeliverGroup{ 624 Clients: mockDeliverClients, 625 ChannelID: "testchannel", 626 Signer: &mock.SignerSerializer{}, 627 Certificate: tls.Certificate{ 628 Certificate: [][]byte{[]byte("test")}, 629 }, 630 TxID: "txid0", 631 } 632 err = dg.Wait(context.Background()) 633 g.Expect(err.Error()).To(ContainSubstring("unexpected response type")) 634 635 // failure - both connections return error 636 mockConn = &mock.Deliver{} 637 mockConn.RecvReturns(nil, errors.New("barbeque")) 638 mockConn2 := &mock.Deliver{} 639 mockConn2.RecvReturns(nil, errors.New("tofu")) 640 mockDeliverClients = []*DeliverClient{ 641 { 642 Connection: mockConn, 643 Address: "peerBBQ", 644 }, 645 { 646 Connection: mockConn2, 647 Address: "peerTOFU", 648 }, 649 } 650 dg = DeliverGroup{ 651 Clients: mockDeliverClients, 652 ChannelID: "testchannel", 653 Signer: &mock.SignerSerializer{}, 654 Certificate: tls.Certificate{ 655 Certificate: [][]byte{[]byte("test")}, 656 }, 657 TxID: "txid0", 658 } 659 err = dg.Wait(context.Background()) 660 g.Expect(err.Error()).To(SatisfyAny( 661 ContainSubstring("barbeque"), 662 ContainSubstring("tofu"))) 663 } 664 665 func TestChaincodeInvokeOrQuery_waitForEvent(t *testing.T) { 666 defer resetFlags() 667 668 waitForEvent = true 669 mockCF, err := getMockChaincodeCmdFactory() 670 require.NoError(t, err) 671 peerAddresses = []string{"peer0", "peer1"} 672 channelID := "testchannel" 673 txID := "txid0" 674 675 t.Run("success - deliver clients returns event with expected txid", func(t *testing.T) { 676 _, err = ChaincodeInvokeOrQuery( 677 &pb.ChaincodeSpec{}, 678 channelID, 679 txID, 680 true, 681 mockCF.Signer, 682 mockCF.Certificate, 683 mockCF.EndorserClients, 684 mockCF.DeliverClients, 685 mockCF.BroadcastClient, 686 ) 687 require.NoError(t, err) 688 }) 689 690 t.Run("success - one deliver client first receives block without txid and then one with txid", func(t *testing.T) { 691 filteredBlocks := []*pb.FilteredBlock{ 692 createFilteredBlock(pb.TxValidationCode_VALID, "theseare", "notthetxidsyouarelookingfor"), 693 createFilteredBlock(pb.TxValidationCode_VALID, "txid0"), 694 } 695 mockDCTwoBlocks := getMockDeliverClientRespondsWithFilteredBlocks(filteredBlocks) 696 mockDC := getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_VALID, "txid0") 697 mockDeliverClients := []pb.DeliverClient{mockDCTwoBlocks, mockDC} 698 699 _, err = ChaincodeInvokeOrQuery( 700 &pb.ChaincodeSpec{}, 701 channelID, 702 txID, 703 true, 704 mockCF.Signer, 705 mockCF.Certificate, 706 mockCF.EndorserClients, 707 mockDeliverClients, 708 mockCF.BroadcastClient, 709 ) 710 require.NoError(t, err) 711 }) 712 713 t.Run("failure - one of the deliver clients returns error", func(t *testing.T) { 714 mockDCErr := getMockDeliverClientWithErr("moist") 715 mockDC := getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_VALID, "txid0") 716 mockDeliverClients := []pb.DeliverClient{mockDCErr, mockDC} 717 718 _, err = ChaincodeInvokeOrQuery( 719 &pb.ChaincodeSpec{}, 720 channelID, 721 txID, 722 true, 723 mockCF.Signer, 724 mockCF.Certificate, 725 mockCF.EndorserClients, 726 mockDeliverClients, 727 mockCF.BroadcastClient, 728 ) 729 require.Error(t, err) 730 require.Contains(t, err.Error(), "moist") 731 }) 732 733 t.Run("failure - transaction committed with non-success validation code", func(t *testing.T) { 734 mockDC := getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_VALID, "txid0") 735 mockDCFail := getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_ENDORSEMENT_POLICY_FAILURE, "txid0") 736 mockDeliverClients := []pb.DeliverClient{mockDCFail, mockDC} 737 738 _, err = ChaincodeInvokeOrQuery( 739 &pb.ChaincodeSpec{}, 740 channelID, 741 txID, 742 true, 743 mockCF.Signer, 744 mockCF.Certificate, 745 mockCF.EndorserClients, 746 mockDeliverClients, 747 mockCF.BroadcastClient, 748 ) 749 require.Error(t, err) 750 require.Equal(t, err.Error(), "transaction invalidated with status (ENDORSEMENT_POLICY_FAILURE)") 751 }) 752 753 t.Run("failure - deliver returns response status instead of block", func(t *testing.T) { 754 mockDC := &mock.PeerDeliverClient{} 755 mockDF := &mock.Deliver{} 756 resp := &pb.DeliverResponse{ 757 Type: &pb.DeliverResponse_Status{ 758 Status: cb.Status_FORBIDDEN, 759 }, 760 } 761 mockDF.RecvReturns(resp, nil) 762 mockDC.DeliverFilteredReturns(mockDF, nil) 763 mockDeliverClients := []pb.DeliverClient{mockDC} 764 _, err = ChaincodeInvokeOrQuery( 765 &pb.ChaincodeSpec{}, 766 channelID, 767 txID, 768 true, 769 mockCF.Signer, 770 mockCF.Certificate, 771 mockCF.EndorserClients, 772 mockDeliverClients, 773 mockCF.BroadcastClient, 774 ) 775 require.Error(t, err) 776 require.Equal(t, err.Error(), "deliver completed with status (FORBIDDEN) before txid received") 777 }) 778 779 t.Run(" failure - timeout occurs - both deliver clients don't return an event with the expected txid before timeout", func(t *testing.T) { 780 delayChan := make(chan struct{}) 781 mockDCDelay := getMockDeliverClientRespondAfterDelay(delayChan, pb.TxValidationCode_VALID, "txid0") 782 mockDeliverClients := []pb.DeliverClient{mockDCDelay, mockDCDelay} 783 waitForEventTimeout = 10 * time.Millisecond 784 785 _, err = ChaincodeInvokeOrQuery( 786 &pb.ChaincodeSpec{}, 787 channelID, 788 txID, 789 true, 790 mockCF.Signer, 791 mockCF.Certificate, 792 mockCF.EndorserClients, 793 mockDeliverClients, 794 mockCF.BroadcastClient, 795 ) 796 require.Error(t, err) 797 require.Contains(t, err.Error(), "timed out") 798 close(delayChan) 799 }) 800 } 801 802 func TestProcessProposals(t *testing.T) { 803 // Build clients that return a range of status codes (for verifying each client is called). 804 mockClients := []pb.EndorserClient{} 805 for i := 2; i <= 5; i++ { 806 response := &pb.ProposalResponse{ 807 Response: &pb.Response{Status: int32(i * 100)}, 808 Endorsement: &pb.Endorsement{}, 809 } 810 mockClients = append(mockClients, common.GetMockEndorserClient(response, nil)) 811 } 812 mockErrorClient := common.GetMockEndorserClient(nil, errors.New("failed to call endorser")) 813 signedProposal := &pb.SignedProposal{} 814 t.Run("should process a proposal for a single peer", func(t *testing.T) { 815 responses, err := processProposals([]pb.EndorserClient{mockClients[0]}, signedProposal) 816 require.NoError(t, err) 817 require.Len(t, responses, 1) 818 require.Equal(t, responses[0].Response.Status, int32(200)) 819 }) 820 t.Run("should process a proposal for multiple peers", func(t *testing.T) { 821 responses, err := processProposals(mockClients, signedProposal) 822 require.NoError(t, err) 823 require.Len(t, responses, 4) 824 // Sort the statuses (as they may turn up in different order) before comparing. 825 statuses := []int32{} 826 for _, response := range responses { 827 statuses = append(statuses, response.Response.Status) 828 } 829 sort.Slice(statuses, func(i, j int) bool { return statuses[i] < statuses[j] }) 830 require.EqualValues(t, []int32{200, 300, 400, 500}, statuses) 831 }) 832 t.Run("should return an error from processing a proposal for a single peer", func(t *testing.T) { 833 responses, err := processProposals([]pb.EndorserClient{mockErrorClient}, signedProposal) 834 require.EqualError(t, err, "failed to call endorser") 835 require.Nil(t, responses) 836 }) 837 t.Run("should return an error from processing a proposal for a single peer within multiple peers", func(t *testing.T) { 838 responses, err := processProposals([]pb.EndorserClient{mockClients[0], mockErrorClient, mockClients[1]}, signedProposal) 839 require.EqualError(t, err, "failed to call endorser") 840 require.Nil(t, responses) 841 }) 842 }