github.com/yacovm/fabric@v2.0.0-alpha.0.20191128145320-c5d4087dc723+incompatible/internal/peer/chaincode/common_test.go (about)

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