github.com/lzy4123/fabric@v2.1.1+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/policydsl" 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 sampleCollectionConfigGoodNoMaxPeerCountOrRequiredPeerCount = `[ 214 { 215 "name": "foo", 216 "policy": "OR('A.member', 'B.member')", 217 "blockToLive":10, 218 "memberOnlyRead": true, 219 "memberOnlyWrite": true 220 } 221 ]` 222 223 const sampleCollectionConfigGoodWithSignaturePolicy = `[ 224 { 225 "name": "foo", 226 "policy": "OR('A.member', 'B.member')", 227 "requiredPeerCount": 3, 228 "maxPeerCount": 483279847, 229 "blockToLive":10, 230 "memberOnlyRead": true, 231 "memberOnlyWrite": true, 232 "endorsementPolicy": { 233 "signaturePolicy": "OR('A.member', 'B.member')" 234 } 235 } 236 ]` 237 238 const sampleCollectionConfigGoodWithChannelConfigPolicy = `[ 239 { 240 "name": "foo", 241 "policy": "OR('A.member', 'B.member')", 242 "requiredPeerCount": 3, 243 "maxPeerCount": 483279847, 244 "blockToLive":10, 245 "memberOnlyRead": true, 246 "memberOnlyWrite": true, 247 "endorsementPolicy": { 248 "channelConfigPolicy": "/Channel/Application/Endorsement" 249 } 250 } 251 ]` 252 253 const sampleCollectionConfigBad = `[ 254 { 255 "name": "foo", 256 "policy": "barf", 257 "requiredPeerCount": 3, 258 "maxPeerCount": 483279847 259 } 260 ]` 261 262 const sampleCollectionConfigBadInvalidSignaturePolicy = `[ 263 { 264 "name": "foo", 265 "policy": "OR('A.member', 'B.member')", 266 "requiredPeerCount": 3, 267 "maxPeerCount": 483279847, 268 "blockToLive":10, 269 "memberOnlyRead": true, 270 "memberOnlyWrite": true, 271 "endorsementPolicy": { 272 "signaturePolicy": "invalid" 273 } 274 } 275 ]` 276 277 const sampleCollectionConfigBadSignaturePolicyAndChannelConfigPolicy = `[ 278 { 279 "name": "foo", 280 "policy": "OR('A.member', 'B.member')", 281 "requiredPeerCount": 3, 282 "maxPeerCount": 483279847, 283 "blockToLive":10, 284 "memberOnlyRead": true, 285 "memberOnlyWrite": true, 286 "endorsementPolicy": { 287 "signaturePolicy": "OR('A.member', 'B.member')", 288 "channelConfigPolicy": "/Channel/Application/Endorsement" 289 } 290 } 291 ]` 292 293 func TestCollectionParsing(t *testing.T) { 294 ccp, ccpBytes, err := getCollectionConfigFromBytes([]byte(sampleCollectionConfigGood)) 295 assert.NoError(t, err) 296 assert.NotNil(t, ccp) 297 assert.NotNil(t, ccpBytes) 298 conf := ccp.Config[0].GetStaticCollectionConfig() 299 pol, _ := policydsl.FromString("OR('A.member', 'B.member')") 300 assert.Equal(t, 3, int(conf.RequiredPeerCount)) 301 assert.Equal(t, 483279847, int(conf.MaximumPeerCount)) 302 assert.Equal(t, "foo", conf.Name) 303 assert.True(t, proto.Equal(pol, conf.MemberOrgsPolicy.GetSignaturePolicy())) 304 assert.Equal(t, 10, int(conf.BlockToLive)) 305 assert.Equal(t, true, conf.MemberOnlyRead) 306 assert.Nil(t, conf.EndorsementPolicy) 307 t.Logf("conf=%s", conf) 308 309 // Test default values for RequiredPeerCount and MaxPeerCount 310 ccp, ccpBytes, err = getCollectionConfigFromBytes([]byte(sampleCollectionConfigGoodNoMaxPeerCountOrRequiredPeerCount)) 311 assert.NoError(t, err) 312 assert.NotNil(t, ccp) 313 assert.NotNil(t, ccpBytes) 314 conf = ccp.Config[0].GetStaticCollectionConfig() 315 pol, _ = policydsl.FromString("OR('A.member', 'B.member')") 316 assert.Equal(t, 0, int(conf.RequiredPeerCount)) 317 assert.Equal(t, 1, int(conf.MaximumPeerCount)) 318 assert.Equal(t, "foo", conf.Name) 319 assert.True(t, proto.Equal(pol, conf.MemberOrgsPolicy.GetSignaturePolicy())) 320 assert.Equal(t, 10, int(conf.BlockToLive)) 321 assert.Equal(t, true, conf.MemberOnlyRead) 322 assert.Nil(t, conf.EndorsementPolicy) 323 t.Logf("conf=%s", conf) 324 325 ccp, ccpBytes, err = getCollectionConfigFromBytes([]byte(sampleCollectionConfigGoodWithSignaturePolicy)) 326 assert.NoError(t, err) 327 assert.NotNil(t, ccp) 328 assert.NotNil(t, ccpBytes) 329 conf = ccp.Config[0].GetStaticCollectionConfig() 330 pol, _ = policydsl.FromString("OR('A.member', 'B.member')") 331 assert.Equal(t, 3, int(conf.RequiredPeerCount)) 332 assert.Equal(t, 483279847, int(conf.MaximumPeerCount)) 333 assert.Equal(t, "foo", conf.Name) 334 assert.True(t, proto.Equal(pol, conf.MemberOrgsPolicy.GetSignaturePolicy())) 335 assert.Equal(t, 10, int(conf.BlockToLive)) 336 assert.Equal(t, true, conf.MemberOnlyRead) 337 assert.True(t, proto.Equal(pol, conf.EndorsementPolicy.GetSignaturePolicy())) 338 t.Logf("conf=%s", conf) 339 340 ccp, ccpBytes, err = getCollectionConfigFromBytes([]byte(sampleCollectionConfigGoodWithChannelConfigPolicy)) 341 assert.NoError(t, err) 342 assert.NotNil(t, ccp) 343 assert.NotNil(t, ccpBytes) 344 conf = ccp.Config[0].GetStaticCollectionConfig() 345 pol, _ = policydsl.FromString("OR('A.member', 'B.member')") 346 assert.Equal(t, 3, int(conf.RequiredPeerCount)) 347 assert.Equal(t, 483279847, int(conf.MaximumPeerCount)) 348 assert.Equal(t, "foo", conf.Name) 349 assert.True(t, proto.Equal(pol, conf.MemberOrgsPolicy.GetSignaturePolicy())) 350 assert.Equal(t, 10, int(conf.BlockToLive)) 351 assert.Equal(t, true, conf.MemberOnlyRead) 352 assert.Equal(t, "/Channel/Application/Endorsement", conf.EndorsementPolicy.GetChannelConfigPolicyReference()) 353 t.Logf("conf=%s", conf) 354 355 failureTests := []struct { 356 name string 357 collectionConfig string 358 expectedErr string 359 }{ 360 { 361 name: "Invalid member orgs policy", 362 collectionConfig: sampleCollectionConfigBad, 363 expectedErr: "invalid policy barf: unrecognized token 'barf' in policy string", 364 }, 365 { 366 name: "Invalid collection config", 367 collectionConfig: "barf", 368 expectedErr: "could not parse the collection configuration: invalid character 'b' looking for beginning of value", 369 }, 370 { 371 name: "Invalid signature policy", 372 collectionConfig: sampleCollectionConfigBadInvalidSignaturePolicy, 373 expectedErr: `invalid endorsement policy [&chaincode.endorsementPolicy{ChannelConfigPolicy:"", SignaturePolicy:"invalid"}]: invalid signature policy: invalid`, 374 }, 375 { 376 name: "Signature policy and channel config policy both specified", 377 collectionConfig: sampleCollectionConfigBadSignaturePolicyAndChannelConfigPolicy, 378 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"`, 379 }, 380 } 381 382 for _, test := range failureTests { 383 t.Run(test.name, func(t *testing.T) { 384 ccp, ccpBytes, err = getCollectionConfigFromBytes([]byte(test.collectionConfig)) 385 assert.EqualError(t, err, test.expectedErr) 386 assert.Nil(t, ccp) 387 assert.Nil(t, ccpBytes) 388 }) 389 } 390 } 391 392 func TestValidatePeerConnectionParams(t *testing.T) { 393 defer resetFlags() 394 defer viper.Reset() 395 assert := assert.New(t) 396 cleanup := configtest.SetDevFabricConfigPath(t) 397 defer cleanup() 398 399 // TLS disabled 400 viper.Set("peer.tls.enabled", false) 401 402 // failure - more than one peer and TLS root cert - not invoke 403 resetFlags() 404 peerAddresses = []string{"peer0", "peer1"} 405 tlsRootCertFiles = []string{"cert0", "cert1"} 406 err := validatePeerConnectionParameters("query") 407 assert.Error(err) 408 assert.Contains(err.Error(), "command can only be executed against one peer") 409 410 // success - peer provided and no TLS root certs 411 // TLS disabled 412 resetFlags() 413 peerAddresses = []string{"peer0"} 414 err = validatePeerConnectionParameters("query") 415 assert.NoError(err) 416 assert.Nil(tlsRootCertFiles) 417 418 // success - more TLS root certs than peers 419 // TLS disabled 420 resetFlags() 421 peerAddresses = []string{"peer0"} 422 tlsRootCertFiles = []string{"cert0", "cert1"} 423 err = validatePeerConnectionParameters("invoke") 424 assert.NoError(err) 425 assert.Nil(tlsRootCertFiles) 426 427 // success - multiple peers and no TLS root certs - invoke 428 // TLS disabled 429 resetFlags() 430 peerAddresses = []string{"peer0", "peer1"} 431 err = validatePeerConnectionParameters("invoke") 432 assert.NoError(err) 433 assert.Nil(tlsRootCertFiles) 434 435 // TLS enabled 436 viper.Set("peer.tls.enabled", true) 437 438 // failure - uneven number of peers and TLS root certs - invoke 439 // TLS enabled 440 resetFlags() 441 peerAddresses = []string{"peer0", "peer1"} 442 tlsRootCertFiles = []string{"cert0"} 443 err = validatePeerConnectionParameters("invoke") 444 assert.Error(err) 445 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))) 446 447 // success - more than one peer and TLS root certs - invoke 448 // TLS enabled 449 resetFlags() 450 peerAddresses = []string{"peer0", "peer1"} 451 tlsRootCertFiles = []string{"cert0", "cert1"} 452 err = validatePeerConnectionParameters("invoke") 453 assert.NoError(err) 454 455 // failure - connection profile doesn't exist 456 resetFlags() 457 connectionProfile = "blah" 458 err = validatePeerConnectionParameters("invoke") 459 assert.Error(err) 460 assert.Contains(err.Error(), "error reading connection profile") 461 462 // failure - connection profile has peer defined in channel config but 463 // not in peer config 464 resetFlags() 465 channelID = "mychannel" 466 connectionProfile = "testdata/connectionprofile-uneven.yaml" 467 err = validatePeerConnectionParameters("invoke") 468 assert.Error(err) 469 assert.Contains(err.Error(), "defined in the channel config but doesn't have associated peer config") 470 471 // success - connection profile exists 472 resetFlags() 473 channelID = "mychannel" 474 connectionProfile = "testdata/connectionprofile.yaml" 475 err = validatePeerConnectionParameters("invoke") 476 assert.NoError(err) 477 } 478 479 func TestInitCmdFactoryFailures(t *testing.T) { 480 defer resetFlags() 481 assert := assert.New(t) 482 483 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 484 assert.Nil(err) 485 486 // failure validating peer connection parameters 487 resetFlags() 488 peerAddresses = []string{"peer0", "peer1"} 489 tlsRootCertFiles = []string{"cert0", "cert1"} 490 cf, err := InitCmdFactory("query", true, false, cryptoProvider) 491 assert.Error(err) 492 assert.Contains(err.Error(), "error validating peer connection parameters: 'query' command can only be executed against one peer") 493 assert.Nil(cf) 494 495 // failure - no peers supplied and endorser client is needed 496 resetFlags() 497 peerAddresses = []string{} 498 cf, err = InitCmdFactory("query", true, false, cryptoProvider) 499 assert.Error(err) 500 assert.Contains(err.Error(), "no endorser clients retrieved") 501 assert.Nil(cf) 502 503 // failure - orderer client is needed, ordering endpoint is empty and no 504 // endorser client supplied 505 resetFlags() 506 peerAddresses = nil 507 cf, err = InitCmdFactory("invoke", false, true, cryptoProvider) 508 assert.Error(err) 509 assert.Contains(err.Error(), "no ordering endpoint or endorser client supplied") 510 assert.Nil(cf) 511 } 512 513 func TestDeliverGroupConnect(t *testing.T) { 514 defer resetFlags() 515 g := NewGomegaWithT(t) 516 517 // success 518 mockDeliverClients := []*DeliverClient{ 519 { 520 Client: getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_VALID, "txid0"), 521 Address: "peer0", 522 }, 523 { 524 Client: getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_VALID, "txid0"), 525 Address: "peer1", 526 }, 527 } 528 dg := DeliverGroup{ 529 Clients: mockDeliverClients, 530 ChannelID: "testchannel", 531 Signer: &mock.SignerSerializer{}, 532 Certificate: tls.Certificate{ 533 Certificate: [][]byte{[]byte("test")}, 534 }, 535 TxID: "txid0", 536 } 537 err := dg.Connect(context.Background()) 538 g.Expect(err).To(BeNil()) 539 540 // failure - DeliverFiltered returns error 541 mockDC := &mock.PeerDeliverClient{} 542 mockDC.DeliverFilteredReturns(nil, errors.New("icecream")) 543 mockDeliverClients = []*DeliverClient{ 544 { 545 Client: mockDC, 546 Address: "peer0", 547 }, 548 } 549 dg = DeliverGroup{ 550 Clients: mockDeliverClients, 551 ChannelID: "testchannel", 552 Signer: &mock.SignerSerializer{}, 553 Certificate: tls.Certificate{ 554 Certificate: [][]byte{[]byte("test")}, 555 }, 556 TxID: "txid0", 557 } 558 err = dg.Connect(context.Background()) 559 g.Expect(err.Error()).To(ContainSubstring("error connecting to deliver filtered")) 560 g.Expect(err.Error()).To(ContainSubstring("icecream")) 561 562 // failure - Send returns error 563 mockD := &mock.Deliver{} 564 mockD.SendReturns(errors.New("blah")) 565 mockDC.DeliverFilteredReturns(mockD, nil) 566 mockDeliverClients = []*DeliverClient{ 567 { 568 Client: mockDC, 569 Address: "peer0", 570 }, 571 } 572 dg = DeliverGroup{ 573 Clients: mockDeliverClients, 574 ChannelID: "testchannel", 575 Signer: &mock.SignerSerializer{}, 576 Certificate: tls.Certificate{ 577 Certificate: [][]byte{[]byte("test")}, 578 }, 579 TxID: "txid0", 580 } 581 err = dg.Connect(context.Background()) 582 g.Expect(err.Error()).To(ContainSubstring("error sending deliver seek info")) 583 g.Expect(err.Error()).To(ContainSubstring("blah")) 584 585 // failure - deliver registration timeout 586 delayChan := make(chan struct{}) 587 mockDCDelay := getMockDeliverClientRegisterAfterDelay(delayChan) 588 mockDeliverClients = []*DeliverClient{ 589 { 590 Client: mockDCDelay, 591 Address: "peer0", 592 }, 593 } 594 ctx, cancelFunc := context.WithTimeout(context.Background(), 10*time.Millisecond) 595 defer cancelFunc() 596 dg = DeliverGroup{ 597 Clients: mockDeliverClients, 598 ChannelID: "testchannel", 599 Signer: &mock.SignerSerializer{}, 600 Certificate: tls.Certificate{ 601 Certificate: [][]byte{[]byte("test")}, 602 }, 603 TxID: "txid0", 604 } 605 err = dg.Connect(ctx) 606 g.Expect(err.Error()).To(ContainSubstring("timed out waiting for connection to deliver on all peers")) 607 close(delayChan) 608 } 609 610 func TestDeliverGroupWait(t *testing.T) { 611 defer resetFlags() 612 g := NewGomegaWithT(t) 613 614 // success 615 mockConn := &mock.Deliver{} 616 filteredResp := &pb.DeliverResponse{ 617 Type: &pb.DeliverResponse_FilteredBlock{FilteredBlock: createFilteredBlock(pb.TxValidationCode_VALID, "txid0")}, 618 } 619 mockConn.RecvReturns(filteredResp, nil) 620 mockDeliverClients := []*DeliverClient{ 621 { 622 Connection: mockConn, 623 Address: "peer0", 624 }, 625 } 626 dg := DeliverGroup{ 627 Clients: mockDeliverClients, 628 ChannelID: "testchannel", 629 Signer: &mock.SignerSerializer{}, 630 Certificate: tls.Certificate{ 631 Certificate: [][]byte{[]byte("test")}, 632 }, 633 TxID: "txid0", 634 } 635 err := dg.Wait(context.Background()) 636 g.Expect(err).To(BeNil()) 637 638 // failure - Recv returns error 639 mockConn = &mock.Deliver{} 640 mockConn.RecvReturns(nil, errors.New("avocado")) 641 mockDeliverClients = []*DeliverClient{ 642 { 643 Connection: mockConn, 644 Address: "peer0", 645 }, 646 } 647 dg = DeliverGroup{ 648 Clients: mockDeliverClients, 649 ChannelID: "testchannel", 650 Signer: &mock.SignerSerializer{}, 651 Certificate: tls.Certificate{ 652 Certificate: [][]byte{[]byte("test")}, 653 }, 654 TxID: "txid0", 655 } 656 err = dg.Wait(context.Background()) 657 g.Expect(err.Error()).To(ContainSubstring("error receiving from deliver filtered")) 658 g.Expect(err.Error()).To(ContainSubstring("avocado")) 659 660 // failure - Recv returns unexpected type 661 mockConn = &mock.Deliver{} 662 resp := &pb.DeliverResponse{ 663 Type: &pb.DeliverResponse_Block{}, 664 } 665 mockConn.RecvReturns(resp, nil) 666 mockDeliverClients = []*DeliverClient{ 667 { 668 Connection: mockConn, 669 Address: "peer0", 670 }, 671 } 672 dg = DeliverGroup{ 673 Clients: mockDeliverClients, 674 ChannelID: "testchannel", 675 Signer: &mock.SignerSerializer{}, 676 Certificate: tls.Certificate{ 677 Certificate: [][]byte{[]byte("test")}, 678 }, 679 TxID: "txid0", 680 } 681 err = dg.Wait(context.Background()) 682 g.Expect(err.Error()).To(ContainSubstring("unexpected response type")) 683 684 // failure - both connections return error 685 mockConn = &mock.Deliver{} 686 mockConn.RecvReturns(nil, errors.New("barbeque")) 687 mockConn2 := &mock.Deliver{} 688 mockConn2.RecvReturns(nil, errors.New("tofu")) 689 mockDeliverClients = []*DeliverClient{ 690 { 691 Connection: mockConn, 692 Address: "peerBBQ", 693 }, 694 { 695 Connection: mockConn2, 696 Address: "peerTOFU", 697 }, 698 } 699 dg = DeliverGroup{ 700 Clients: mockDeliverClients, 701 ChannelID: "testchannel", 702 Signer: &mock.SignerSerializer{}, 703 Certificate: tls.Certificate{ 704 Certificate: [][]byte{[]byte("test")}, 705 }, 706 TxID: "txid0", 707 } 708 err = dg.Wait(context.Background()) 709 g.Expect(err.Error()).To(SatisfyAny( 710 ContainSubstring("barbeque"), 711 ContainSubstring("tofu"))) 712 } 713 714 func TestChaincodeInvokeOrQuery_waitForEvent(t *testing.T) { 715 defer resetFlags() 716 717 waitForEvent = true 718 mockCF, err := getMockChaincodeCmdFactory() 719 assert.NoError(t, err) 720 peerAddresses = []string{"peer0", "peer1"} 721 channelID := "testchannel" 722 txID := "txid0" 723 724 t.Run("success - deliver clients returns event with expected txid", func(t *testing.T) { 725 _, err = ChaincodeInvokeOrQuery( 726 &pb.ChaincodeSpec{}, 727 channelID, 728 txID, 729 true, 730 mockCF.Signer, 731 mockCF.Certificate, 732 mockCF.EndorserClients, 733 mockCF.DeliverClients, 734 mockCF.BroadcastClient, 735 ) 736 assert.NoError(t, err) 737 }) 738 739 t.Run("success - one deliver client first receives block without txid and then one with txid", func(t *testing.T) { 740 filteredBlocks := []*pb.FilteredBlock{ 741 createFilteredBlock(pb.TxValidationCode_VALID, "theseare", "notthetxidsyouarelookingfor"), 742 createFilteredBlock(pb.TxValidationCode_VALID, "txid0"), 743 } 744 mockDCTwoBlocks := getMockDeliverClientRespondsWithFilteredBlocks(filteredBlocks) 745 mockDC := getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_VALID, "txid0") 746 mockDeliverClients := []pb.DeliverClient{mockDCTwoBlocks, mockDC} 747 748 _, err = ChaincodeInvokeOrQuery( 749 &pb.ChaincodeSpec{}, 750 channelID, 751 txID, 752 true, 753 mockCF.Signer, 754 mockCF.Certificate, 755 mockCF.EndorserClients, 756 mockDeliverClients, 757 mockCF.BroadcastClient, 758 ) 759 assert.NoError(t, err) 760 }) 761 762 t.Run("failure - one of the deliver clients returns error", func(t *testing.T) { 763 mockDCErr := getMockDeliverClientWithErr("moist") 764 mockDC := getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_VALID, "txid0") 765 mockDeliverClients := []pb.DeliverClient{mockDCErr, mockDC} 766 767 _, err = ChaincodeInvokeOrQuery( 768 &pb.ChaincodeSpec{}, 769 channelID, 770 txID, 771 true, 772 mockCF.Signer, 773 mockCF.Certificate, 774 mockCF.EndorserClients, 775 mockDeliverClients, 776 mockCF.BroadcastClient, 777 ) 778 assert.Error(t, err) 779 assert.Contains(t, err.Error(), "moist") 780 }) 781 782 t.Run("failure - transaction committed with non-success validation code", func(t *testing.T) { 783 mockDC := getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_VALID, "txid0") 784 mockDCFail := getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_ENDORSEMENT_POLICY_FAILURE, "txid0") 785 mockDeliverClients := []pb.DeliverClient{mockDCFail, mockDC} 786 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(), "transaction invalidated with status (ENDORSEMENT_POLICY_FAILURE)") 800 }) 801 802 t.Run("failure - deliver returns response status instead of block", func(t *testing.T) { 803 mockDC := &mock.PeerDeliverClient{} 804 mockDF := &mock.Deliver{} 805 resp := &pb.DeliverResponse{ 806 Type: &pb.DeliverResponse_Status{ 807 Status: cb.Status_FORBIDDEN, 808 }, 809 } 810 mockDF.RecvReturns(resp, nil) 811 mockDC.DeliverFilteredReturns(mockDF, nil) 812 mockDeliverClients := []pb.DeliverClient{mockDC} 813 _, err = ChaincodeInvokeOrQuery( 814 &pb.ChaincodeSpec{}, 815 channelID, 816 txID, 817 true, 818 mockCF.Signer, 819 mockCF.Certificate, 820 mockCF.EndorserClients, 821 mockDeliverClients, 822 mockCF.BroadcastClient, 823 ) 824 assert.Error(t, err) 825 assert.Equal(t, err.Error(), "deliver completed with status (FORBIDDEN) before txid received") 826 }) 827 828 t.Run(" failure - timeout occurs - both deliver clients don't return an event with the expected txid before timeout", func(t *testing.T) { 829 delayChan := make(chan struct{}) 830 mockDCDelay := getMockDeliverClientRespondAfterDelay(delayChan, pb.TxValidationCode_VALID, "txid0") 831 mockDeliverClients := []pb.DeliverClient{mockDCDelay, mockDCDelay} 832 waitForEventTimeout = 10 * time.Millisecond 833 834 _, err = ChaincodeInvokeOrQuery( 835 &pb.ChaincodeSpec{}, 836 channelID, 837 txID, 838 true, 839 mockCF.Signer, 840 mockCF.Certificate, 841 mockCF.EndorserClients, 842 mockDeliverClients, 843 mockCF.BroadcastClient, 844 ) 845 assert.Error(t, err) 846 assert.Contains(t, err.Error(), "timed out") 847 close(delayChan) 848 }) 849 } 850 851 func TestProcessProposals(t *testing.T) { 852 // Build clients that return a range of status codes (for verifying each client is called). 853 mockClients := []pb.EndorserClient{} 854 for i := 2; i <= 5; i++ { 855 response := &pb.ProposalResponse{ 856 Response: &pb.Response{Status: int32(i * 100)}, 857 Endorsement: &pb.Endorsement{}, 858 } 859 mockClients = append(mockClients, common.GetMockEndorserClient(response, nil)) 860 } 861 mockErrorClient := common.GetMockEndorserClient(nil, errors.New("failed to call endorser")) 862 signedProposal := &pb.SignedProposal{} 863 t.Run("should process a proposal for a single peer", func(t *testing.T) { 864 responses, err := processProposals([]pb.EndorserClient{mockClients[0]}, signedProposal) 865 assert.NoError(t, err) 866 assert.Len(t, responses, 1) 867 assert.Equal(t, responses[0].Response.Status, int32(200)) 868 }) 869 t.Run("should process a proposal for multiple peers", func(t *testing.T) { 870 responses, err := processProposals(mockClients, signedProposal) 871 assert.NoError(t, err) 872 assert.Len(t, responses, 4) 873 // Sort the statuses (as they may turn up in different order) before comparing. 874 statuses := []int32{} 875 for _, response := range responses { 876 statuses = append(statuses, response.Response.Status) 877 } 878 sort.Slice(statuses, func(i, j int) bool { return statuses[i] < statuses[j] }) 879 assert.EqualValues(t, []int32{200, 300, 400, 500}, statuses) 880 }) 881 t.Run("should return an error from processing a proposal for a single peer", func(t *testing.T) { 882 responses, err := processProposals([]pb.EndorserClient{mockErrorClient}, signedProposal) 883 assert.EqualError(t, err, "failed to call endorser") 884 assert.Nil(t, responses) 885 }) 886 t.Run("should return an error from processing a proposal for a single peer within multiple peers", func(t *testing.T) { 887 responses, err := processProposals([]pb.EndorserClient{mockClients[0], mockErrorClient, mockClients[1]}, signedProposal) 888 assert.EqualError(t, err, "failed to call endorser") 889 assert.Nil(t, responses) 890 }) 891 }