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