github.com/kaituanwang/hyperledger@v2.0.1+incompatible/discovery/cmd/endorsers_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package discovery_test
     8  
     9  import (
    10  	"bytes"
    11  	"testing"
    12  
    13  	discprotos "github.com/hyperledger/fabric-protos-go/discovery"
    14  	"github.com/hyperledger/fabric-protos-go/msp"
    15  	"github.com/hyperledger/fabric/cmd/common"
    16  	. "github.com/hyperledger/fabric/discovery/client"
    17  	discovery "github.com/hyperledger/fabric/discovery/cmd"
    18  	"github.com/hyperledger/fabric/discovery/cmd/mocks"
    19  	"github.com/hyperledger/fabric/protoutil"
    20  	"github.com/pkg/errors"
    21  	"github.com/stretchr/testify/assert"
    22  	"github.com/stretchr/testify/mock"
    23  )
    24  
    25  func TestEndorserCmd(t *testing.T) {
    26  	server := "peer0"
    27  	channel := "mychannel"
    28  	stub := &mocks.Stub{}
    29  	parser := &mocks.ResponseParser{}
    30  
    31  	t.Run("no server supplied", func(t *testing.T) {
    32  		cmd := discovery.NewEndorsersCmd(stub, parser)
    33  		cmd.SetChannel(&channel)
    34  
    35  		err := cmd.Execute(common.Config{})
    36  		assert.Equal(t, err.Error(), "no server specified")
    37  	})
    38  
    39  	t.Run("no channel supplied", func(t *testing.T) {
    40  		cmd := discovery.NewEndorsersCmd(stub, parser)
    41  		cmd.SetServer(&server)
    42  
    43  		err := cmd.Execute(common.Config{})
    44  		assert.Equal(t, err.Error(), "no channel specified")
    45  	})
    46  
    47  	t.Run("Endorsement query with no chaincodes", func(t *testing.T) {
    48  		cmd := discovery.NewEndorsersCmd(stub, parser)
    49  		cmd.SetServer(&server)
    50  		cmd.SetChannel(&channel)
    51  
    52  		err := cmd.Execute(common.Config{})
    53  		assert.Contains(t, err.Error(), "invocation chain should not be empty")
    54  	})
    55  
    56  	t.Run("Server return error", func(t *testing.T) {
    57  		chaincodes := []string{"mycc"}
    58  		cmd := discovery.NewEndorsersCmd(stub, parser)
    59  		cmd.SetChannel(&channel)
    60  		cmd.SetServer(&server)
    61  		cmd.SetChaincodes(&chaincodes)
    62  		stub.On("Send", server, mock.Anything, mock.Anything).Return(nil, errors.New("deadline exceeded")).Once()
    63  
    64  		err := cmd.Execute(common.Config{})
    65  		assert.Contains(t, err.Error(), "deadline exceeded")
    66  	})
    67  
    68  	t.Run("Endorsement query with no collections succeeds", func(t *testing.T) {
    69  		chaincodes := []string{"mycc"}
    70  		cmd := discovery.NewEndorsersCmd(stub, parser)
    71  		cmd.SetChannel(&channel)
    72  		cmd.SetServer(&server)
    73  		cmd.SetChaincodes(&chaincodes)
    74  		parser.On("ParseResponse", channel, mock.Anything).Return(nil).Once()
    75  		stub.On("Send", server, mock.Anything, mock.Anything).Return(nil, nil).Once()
    76  
    77  		err := cmd.Execute(common.Config{})
    78  		assert.NoError(t, err)
    79  	})
    80  
    81  	t.Run("Endorsement query with collections succeeds", func(t *testing.T) {
    82  		chaincodes := []string{"mycc", "yourcc"}
    83  		collections := map[string]string{
    84  			"mycc": "col1,col2",
    85  		}
    86  
    87  		stub := &mocks.Stub{}
    88  		cmd := discovery.NewEndorsersCmd(stub, parser)
    89  		cmd.SetChannel(&channel)
    90  		cmd.SetServer(&server)
    91  		cmd.SetChaincodes(&chaincodes)
    92  		cmd.SetCollections(&collections)
    93  		parser.On("ParseResponse", channel, mock.Anything).Return(nil).Once()
    94  		stub.On("Send", server, mock.Anything, mock.Anything).Return(nil, nil).Once().Run(func(arg mock.Arguments) {
    95  			// Ensure the stub got the request that corresponds to what the CLI passed in
    96  			req := arg.Get(2).(*Request)
    97  			// Ensure chaincode names in the invocation chain match
    98  			assert.Equal(t, "mycc", req.Queries[0].GetCcQuery().Interests[0].Chaincodes[0].Name)
    99  			// Ensure collection names in the invocation chain match
   100  			assert.Equal(t, []string{"col1", "col2"}, req.Queries[0].GetCcQuery().Interests[0].Chaincodes[0].CollectionNames)
   101  		})
   102  
   103  		err := cmd.Execute(common.Config{})
   104  		assert.NoError(t, err)
   105  		stub.AssertNumberOfCalls(t, "Send", 1)
   106  	})
   107  
   108  	t.Run("Endorsement query with collections that aren't mapped to any chaincode(s)", func(t *testing.T) {
   109  		chaincodes := []string{"mycc", "yourcc"}
   110  		collections := map[string]string{
   111  			"mycc":  "col1,col2",
   112  			"ourcc": "col3",
   113  		}
   114  
   115  		stub := &mocks.Stub{}
   116  		cmd := discovery.NewEndorsersCmd(stub, parser)
   117  		cmd.SetChannel(&channel)
   118  		cmd.SetServer(&server)
   119  		cmd.SetChaincodes(&chaincodes)
   120  		cmd.SetCollections(&collections)
   121  		stub.On("Send", server, mock.Anything, mock.Anything).Return(nil, nil).Once()
   122  
   123  		err := cmd.Execute(common.Config{})
   124  		assert.Contains(t, err.Error(), "a collection specified chaincode ourcc but it wasn't specified with a chaincode flag")
   125  	})
   126  
   127  	t.Run("Endorsement query with collections that aren't mapped to any chaincode(s)", func(t *testing.T) {
   128  		chaincodes := []string{"mycc", "yourcc"}
   129  		collections := map[string]string{
   130  			"mycc":  "col1,col2",
   131  			"ourcc": "col3",
   132  		}
   133  
   134  		stub := &mocks.Stub{}
   135  		cmd := discovery.NewEndorsersCmd(stub, parser)
   136  		cmd.SetChannel(&channel)
   137  		cmd.SetServer(&server)
   138  		cmd.SetChaincodes(&chaincodes)
   139  		cmd.SetCollections(&collections)
   140  		stub.On("Send", server, mock.Anything, mock.Anything).Return(nil, nil).Once()
   141  
   142  		err := cmd.Execute(common.Config{})
   143  		assert.Contains(t, err.Error(), "a collection specified chaincode ourcc but it wasn't specified with a chaincode flag")
   144  	})
   145  }
   146  
   147  func TestParseEndorsementResponse(t *testing.T) {
   148  	buff := &bytes.Buffer{}
   149  	parser := &discovery.EndorserResponseParser{Writer: buff}
   150  	res := &mocks.ServiceResponse{}
   151  
   152  	t.Run("Server returns empty response", func(t *testing.T) {
   153  		defer buff.Reset()
   154  		res.On("Raw").Return(&discprotos.Response{}).Once()
   155  		err := parser.ParseResponse("mychannel", res)
   156  		assert.Contains(t, err.Error(), "empty results")
   157  	})
   158  
   159  	t.Run("Server returns an error", func(t *testing.T) {
   160  		defer buff.Reset()
   161  		res.On("Raw").Return(&discprotos.Response{
   162  			Results: []*discprotos.QueryResult{
   163  				{
   164  					Result: &discprotos.QueryResult_Error{
   165  						Error: &discprotos.Error{
   166  							Content: "internal error",
   167  						},
   168  					},
   169  				},
   170  			},
   171  		}).Once()
   172  		err := parser.ParseResponse("mychannel", res)
   173  		assert.Contains(t, err.Error(), "internal error")
   174  	})
   175  
   176  	t.Run("Server returns a response with the wrong type", func(t *testing.T) {
   177  		defer buff.Reset()
   178  		res.On("Raw").Return(&discprotos.Response{
   179  			Results: []*discprotos.QueryResult{
   180  				{
   181  					Result: &discprotos.QueryResult_Members{
   182  						Members: &discprotos.PeerMembershipResult{PeersByOrg: map[string]*discprotos.Peers{
   183  							"Org1MSP": {},
   184  						}},
   185  					},
   186  				},
   187  			},
   188  		}).Once()
   189  		err := parser.ParseResponse("mychannel", res)
   190  		assert.Contains(t, err.Error(), "server returned response of unexpected type: *discovery.QueryResult")
   191  	})
   192  
   193  	t.Run("Server returns a proper response", func(t *testing.T) {
   194  		defer buff.Reset()
   195  		res.On("Raw").Return(&discprotos.Response{
   196  			Results: []*discprotos.QueryResult{
   197  				{
   198  					Result: endorsersResponse,
   199  				},
   200  			},
   201  		}).Once()
   202  		err := parser.ParseResponse("mychannel", res)
   203  		assert.NoError(t, err)
   204  		assert.Equal(t, expectedEndorsersOutput, buff.String())
   205  	})
   206  }
   207  
   208  var endorsersResponse = &discprotos.QueryResult_CcQueryRes{
   209  	CcQueryRes: &discprotos.ChaincodeQueryResult{
   210  		Content: []*discprotos.EndorsementDescriptor{
   211  			{
   212  				Chaincode: "mycc",
   213  				EndorsersByGroups: map[string]*discprotos.Peers{
   214  					"Org1MSP": {
   215  						Peers: []*discprotos.Peer{
   216  							{
   217  								Identity: protoutil.MarshalOrPanic(&msp.SerializedIdentity{
   218  									Mspid:   "Org1MSP",
   219  									IdBytes: []byte("identity"),
   220  								}),
   221  								StateInfo:      stateInfoMessage(100).Envelope,
   222  								MembershipInfo: aliveMessage(0).Envelope,
   223  							},
   224  						},
   225  					},
   226  				},
   227  				Layouts: []*discprotos.Layout{
   228  					{
   229  						QuantitiesByGroup: map[string]uint32{
   230  							"Org1MSP": 2,
   231  						},
   232  					},
   233  				},
   234  			},
   235  		},
   236  	},
   237  }
   238  
   239  const expectedEndorsersOutput = `[
   240  	{
   241  		"Chaincode": "mycc",
   242  		"EndorsersByGroups": {
   243  			"Org1MSP": [
   244  				{
   245  					"MSPID": "Org1MSP",
   246  					"LedgerHeight": 100,
   247  					"Endpoint": "p0",
   248  					"Identity": "identity"
   249  				}
   250  			]
   251  		},
   252  		"Layouts": [
   253  			{
   254  				"quantities_by_group": {
   255  					"Org1MSP": 2
   256  				}
   257  			}
   258  		]
   259  	}
   260  ]
   261  `