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  }