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