github.com/lzy4123/fabric@v2.1.1+incompatible/internal/peer/chaincode/invoke_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package chaincode 8 9 import ( 10 "context" 11 "errors" 12 "fmt" 13 "testing" 14 "time" 15 16 cb "github.com/hyperledger/fabric-protos-go/common" 17 pb "github.com/hyperledger/fabric-protos-go/peer" 18 "github.com/hyperledger/fabric/bccsp" 19 "github.com/hyperledger/fabric/bccsp/sw" 20 "github.com/hyperledger/fabric/common/flogging/floggingtest" 21 "github.com/hyperledger/fabric/internal/peer/chaincode/mock" 22 "github.com/hyperledger/fabric/internal/peer/common" 23 "github.com/hyperledger/fabric/msp" 24 "github.com/hyperledger/fabric/protoutil" 25 "github.com/spf13/viper" 26 "github.com/stretchr/testify/assert" 27 "google.golang.org/grpc" 28 ) 29 30 func TestInvokeCmd(t *testing.T) { 31 defer viper.Reset() 32 defer resetFlags() 33 34 resetFlags() 35 mockCF, err := getMockChaincodeCmdFactory() 36 assert.NoError(t, err, "Error getting mock chaincode command factory") 37 38 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 39 assert.NoError(t, err) 40 41 // Error case 0: no channelID specified 42 cmd := invokeCmd(mockCF, cryptoProvider) 43 addFlags(cmd) 44 args := []string{"-n", "example02", "-c", "{\"Args\": [\"invoke\",\"a\",\"b\",\"10\"]}"} 45 cmd.SetArgs(args) 46 err = cmd.Execute() 47 assert.Error(t, err, "'peer chaincode invoke' command should have returned error when called without -C flag") 48 49 // Success case 50 cmd = invokeCmd(mockCF, cryptoProvider) 51 addFlags(cmd) 52 args = []string{"-n", "example02", "-c", "{\"Args\": [\"invoke\",\"a\",\"b\",\"10\"]}", "-C", "mychannel"} 53 cmd.SetArgs(args) 54 err = cmd.Execute() 55 assert.NoError(t, err, "Run chaincode invoke cmd error") 56 57 // set timeout for error cases 58 viper.Set("peer.client.connTimeout", 10*time.Millisecond) 59 60 // Error case 1: no orderer endpoints 61 t.Logf("Start error case 1: no orderer endpoints") 62 getEndorserClient := common.GetEndorserClientFnc 63 getOrdererEndpointOfChain := common.GetOrdererEndpointOfChainFnc 64 getBroadcastClient := common.GetBroadcastClientFnc 65 getDefaultSigner := common.GetDefaultSignerFnc 66 getDeliverClient := common.GetDeliverClientFnc 67 getPeerDeliverClient := common.GetPeerDeliverClientFnc 68 defer func() { 69 common.GetEndorserClientFnc = getEndorserClient 70 common.GetOrdererEndpointOfChainFnc = getOrdererEndpointOfChain 71 common.GetBroadcastClientFnc = getBroadcastClient 72 common.GetDefaultSignerFnc = getDefaultSigner 73 common.GetDeliverClientFnc = getDeliverClient 74 common.GetPeerDeliverClientFnc = getPeerDeliverClient 75 }() 76 common.GetEndorserClientFnc = func(string, string) (pb.EndorserClient, error) { 77 return mockCF.EndorserClients[0], nil 78 } 79 common.GetOrdererEndpointOfChainFnc = func(chainID string, signer common.Signer, endorserClient pb.EndorserClient, cryptoProvider bccsp.BCCSP) ([]string, error) { 80 return []string{}, nil 81 } 82 cmd = invokeCmd(nil, cryptoProvider) 83 addFlags(cmd) 84 args = []string{"-n", "example02", "-c", "{\"Args\": [\"invoke\",\"a\",\"b\",\"10\"]}", "-C", "mychannel"} 85 cmd.SetArgs(args) 86 err = cmd.Execute() 87 assert.Error(t, err) 88 89 // Error case 2: getEndorserClient returns error 90 t.Logf("Start error case 2: getEndorserClient returns error") 91 common.GetEndorserClientFnc = func(string, string) (pb.EndorserClient, error) { 92 return nil, errors.New("error") 93 } 94 err = cmd.Execute() 95 assert.Error(t, err) 96 97 // Error case 3: getDeliverClient returns error 98 t.Logf("Start error case 3: getDeliverClient returns error") 99 common.GetDeliverClientFnc = func(string, string) (pb.Deliver_DeliverClient, error) { 100 return nil, errors.New("error") 101 } 102 err = cmd.Execute() 103 assert.Error(t, err) 104 105 // Error case 4 : getPeerDeliverClient returns error 106 t.Logf("Start error case 4: getPeerDeliverClient returns error") 107 common.GetPeerDeliverClientFnc = func(string, string) (pb.DeliverClient, error) { 108 return nil, errors.New("error") 109 } 110 err = cmd.Execute() 111 assert.Error(t, err) 112 113 // Error case 5: getDefaultSignerFnc returns error 114 t.Logf("Start error case 5: getDefaultSignerFnc returns error") 115 common.GetEndorserClientFnc = func(string, string) (pb.EndorserClient, error) { 116 return mockCF.EndorserClients[0], nil 117 } 118 common.GetPeerDeliverClientFnc = func(string, string) (pb.DeliverClient, error) { 119 return mockCF.DeliverClients[0], nil 120 } 121 common.GetDefaultSignerFnc = func() (msp.SigningIdentity, error) { 122 return nil, errors.New("error") 123 } 124 err = cmd.Execute() 125 assert.Error(t, err) 126 common.GetDefaultSignerFnc = common.GetDefaultSigner 127 128 // Error case 6: getOrdererEndpointOfChainFnc returns error 129 t.Logf("Start error case 6: getOrdererEndpointOfChainFnc returns error") 130 common.GetEndorserClientFnc = func(string, string) (pb.EndorserClient, error) { 131 return mockCF.EndorserClients[0], nil 132 } 133 common.GetOrdererEndpointOfChainFnc = func(chainID string, signer common.Signer, endorserClient pb.EndorserClient, cryptoProvider bccsp.BCCSP) ([]string, error) { 134 return nil, errors.New("error") 135 } 136 err = cmd.Execute() 137 assert.Error(t, err) 138 139 // Error case 7: getBroadcastClient returns error 140 t.Logf("Start error case 7: getBroadcastClient returns error") 141 common.GetOrdererEndpointOfChainFnc = func(chainID string, signer common.Signer, endorserClient pb.EndorserClient, cryptoProvider bccsp.BCCSP) ([]string, error) { 142 return []string{"localhost:9999"}, nil 143 } 144 common.GetBroadcastClientFnc = func() (common.BroadcastClient, error) { 145 return nil, errors.New("error") 146 } 147 err = cmd.Execute() 148 assert.Error(t, err) 149 150 // Success case 151 t.Logf("Start success case") 152 common.GetBroadcastClientFnc = func() (common.BroadcastClient, error) { 153 return mockCF.BroadcastClient, nil 154 } 155 err = cmd.Execute() 156 assert.NoError(t, err) 157 } 158 159 func TestInvokeCmdSimulateESCCPluginResponse(t *testing.T) { 160 defer resetFlags() 161 mockCF, err := getMockChaincodeCmdFactory() 162 assert.NoError(t, err, "Error getting mock chaincode command factory") 163 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 164 assert.NoError(t, err) 165 166 // success case - simulate an ESCC plugin that endorses a chaincode response 167 // with status greater than shim.ERRORTHRESHOLD or even shim.ERROR 168 mockResponse := &pb.ProposalResponse{ 169 Response: &pb.Response{Status: 504}, 170 Endorsement: &pb.Endorsement{}, 171 } 172 mockCF.EndorserClients = []pb.EndorserClient{ 173 common.GetMockEndorserClient(mockResponse, nil), 174 common.GetMockEndorserClient(mockResponse, nil), 175 } 176 177 // set logger to logger with a backend that writes to a byte buffer 178 oldLogger := logger 179 defer func() { logger = oldLogger }() 180 l, recorder := floggingtest.NewTestLogger(t) 181 logger = l 182 183 cmd := invokeCmd(mockCF, cryptoProvider) 184 addFlags(cmd) 185 args := []string{"-n", "example02", "-c", "{\"Args\": [\"invoke\",\"a\",\"b\",\"10\"]}", "-C", "mychannel"} 186 cmd.SetArgs(args) 187 188 err = cmd.Execute() 189 assert.NoError(t, err, "Run chaincode invoke cmd error") 190 191 assert.NotEmpty(t, recorder.MessagesContaining("Chaincode invoke successful"), "missing invoke success log record") 192 assert.NotEmpty(t, recorder.MessagesContaining("result: <nil>"), "missing result log record") 193 } 194 195 func TestInvokeCmdEndorsementError(t *testing.T) { 196 defer resetFlags() 197 mockCF, err := getMockChaincodeCmdFactoryWithErr() 198 assert.NoError(t, err, "Error getting mock chaincode command factory") 199 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 200 assert.NoError(t, err) 201 202 cmd := invokeCmd(mockCF, cryptoProvider) 203 addFlags(cmd) 204 args := []string{"-n", "example02", "-C", "mychannel", "-c", "{\"Args\": [\"invoke\",\"a\",\"b\",\"10\"]}"} 205 cmd.SetArgs(args) 206 err = cmd.Execute() 207 assert.Error(t, err, "Expected error executing invoke command") 208 } 209 210 func TestInvokeCmdEndorsementFailure(t *testing.T) { 211 defer resetFlags() 212 ccRespStatus := [2]int32{502, 400} 213 ccRespPayload := [][]byte{[]byte("Invalid function name"), []byte("Incorrect parameters")} 214 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 215 assert.NoError(t, err) 216 217 for i := 0; i < 2; i++ { 218 mockCF, err := getMockChaincodeCmdFactoryEndorsementFailure(ccRespStatus[i], ccRespPayload[i]) 219 assert.NoError(t, err, "Error getting mock chaincode command factory") 220 221 cmd := invokeCmd(mockCF, cryptoProvider) 222 addFlags(cmd) 223 args := []string{"-C", "mychannel", "-n", "example02", "-c", "{\"Args\": [\"invokeinvalid\",\"a\",\"b\",\"10\"]}"} 224 cmd.SetArgs(args) 225 226 err = cmd.Execute() 227 assert.Error(t, err) 228 assert.Contains(t, err.Error(), "endorsement failure during invoke") 229 assert.Contains(t, err.Error(), fmt.Sprintf("response: status:%d payload:\"%s\"", ccRespStatus[i], ccRespPayload[i])) 230 } 231 } 232 233 // Returns mock chaincode command factory with multiple endorser and deliver clients 234 func getMockChaincodeCmdFactory() (*ChaincodeCmdFactory, error) { 235 signer, err := common.GetDefaultSigner() 236 if err != nil { 237 return nil, err 238 } 239 mockResponse := &pb.ProposalResponse{ 240 Response: &pb.Response{Status: 200}, 241 Endorsement: &pb.Endorsement{}, 242 } 243 mockEndorserClients := []pb.EndorserClient{common.GetMockEndorserClient(mockResponse, nil), common.GetMockEndorserClient(mockResponse, nil)} 244 mockBroadcastClient := common.GetMockBroadcastClient(nil) 245 mockDC := getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_VALID, "txid0") 246 mockDeliverClients := []pb.DeliverClient{mockDC, mockDC} 247 mockCF := &ChaincodeCmdFactory{ 248 EndorserClients: mockEndorserClients, 249 Signer: signer, 250 BroadcastClient: mockBroadcastClient, 251 DeliverClients: mockDeliverClients, 252 } 253 return mockCF, nil 254 } 255 256 // Returns mock chaincode command factory that is constructed with an endorser 257 // client that returns an error for proposal request and a deliver client 258 func getMockChaincodeCmdFactoryWithErr() (*ChaincodeCmdFactory, error) { 259 signer, err := common.GetDefaultSigner() 260 if err != nil { 261 return nil, err 262 } 263 264 errMsg := "invoke error" 265 mockEndorserClients := []pb.EndorserClient{common.GetMockEndorserClient(nil, errors.New(errMsg))} 266 mockBroadcastClient := common.GetMockBroadcastClient(nil) 267 mockDeliverClients := []pb.DeliverClient{getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_INVALID_OTHER_REASON, "txid0")} 268 mockCF := &ChaincodeCmdFactory{ 269 EndorserClients: mockEndorserClients, 270 Signer: signer, 271 BroadcastClient: mockBroadcastClient, 272 DeliverClients: mockDeliverClients, 273 } 274 return mockCF, nil 275 } 276 277 // Returns mock chaincode command factory with an endorser client (that fails) and 278 // a deliver client 279 func getMockChaincodeCmdFactoryEndorsementFailure(ccRespStatus int32, ccRespPayload []byte) (*ChaincodeCmdFactory, error) { 280 signer, err := common.GetDefaultSigner() 281 if err != nil { 282 return nil, err 283 } 284 285 // create a proposal from a ChaincodeInvocationSpec 286 prop, _, err := protoutil.CreateChaincodeProposal(cb.HeaderType_ENDORSER_TRANSACTION, "testchannelid", createCIS(), nil) 287 if err != nil { 288 return nil, fmt.Errorf("Could not create chaincode proposal, err %s\n", err) 289 } 290 291 response := &pb.Response{Status: ccRespStatus, Payload: ccRespPayload} 292 result := []byte("res") 293 294 mockRespFailure, err := protoutil.CreateProposalResponseFailure(prop.Header, prop.Payload, response, result, nil, "foo") 295 if err != nil { 296 297 return nil, fmt.Errorf("Could not create proposal response failure, err %s\n", err) 298 } 299 300 mockEndorserClients := []pb.EndorserClient{common.GetMockEndorserClient(mockRespFailure, nil)} 301 mockBroadcastClient := common.GetMockBroadcastClient(nil) 302 mockDeliverClients := []pb.DeliverClient{getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode(mockRespFailure.Response.Status), "txid0")} 303 mockCF := &ChaincodeCmdFactory{ 304 EndorserClients: mockEndorserClients, 305 Signer: signer, 306 BroadcastClient: mockBroadcastClient, 307 DeliverClients: mockDeliverClients, 308 } 309 return mockCF, nil 310 } 311 312 func createCIS() *pb.ChaincodeInvocationSpec { 313 return &pb.ChaincodeInvocationSpec{ 314 ChaincodeSpec: &pb.ChaincodeSpec{ 315 Type: pb.ChaincodeSpec_GOLANG, 316 ChaincodeId: &pb.ChaincodeID{Name: "chaincode_name"}, 317 Input: &pb.ChaincodeInput{Args: [][]byte{[]byte("arg1"), []byte("arg2")}}}} 318 } 319 320 func getMockDeliverClientResponseWithTxStatusAndID(txStatus pb.TxValidationCode, txID string) *mock.PeerDeliverClient { 321 mockDC := &mock.PeerDeliverClient{} 322 mockDC.DeliverFilteredStub = func(ctx context.Context, opts ...grpc.CallOption) (pb.Deliver_DeliverFilteredClient, error) { 323 return getMockDeliverConnectionResponseWithTxStatusAndID(txStatus, txID), nil 324 } 325 return mockDC 326 } 327 328 func getMockDeliverConnectionResponseWithTxStatusAndID(txStatus pb.TxValidationCode, txID string) *mock.Deliver { 329 mockDF := &mock.Deliver{} 330 resp := &pb.DeliverResponse{ 331 Type: &pb.DeliverResponse_FilteredBlock{ 332 FilteredBlock: createFilteredBlock(txStatus, txID), 333 }, 334 } 335 mockDF.RecvReturns(resp, nil) 336 return mockDF 337 } 338 339 func getMockDeliverClientRespondsWithFilteredBlocks(fb []*pb.FilteredBlock) *mock.PeerDeliverClient { 340 mockDC := &mock.PeerDeliverClient{} 341 mockDC.DeliverFilteredStub = func(ctx context.Context, opts ...grpc.CallOption) (pb.Deliver_DeliverFilteredClient, error) { 342 mockDF := &mock.Deliver{} 343 for i, f := range fb { 344 resp := &pb.DeliverResponse{ 345 Type: &pb.DeliverResponse_FilteredBlock{ 346 FilteredBlock: f, 347 }, 348 } 349 mockDF.RecvReturnsOnCall(i, resp, nil) 350 } 351 return mockDF, nil 352 } 353 return mockDC 354 } 355 356 func getMockDeliverClientRegisterAfterDelay(delayChan chan struct{}) *mock.PeerDeliverClient { 357 mockDC := &mock.PeerDeliverClient{} 358 mockDC.DeliverFilteredStub = func(ctx context.Context, opts ...grpc.CallOption) (pb.Deliver_DeliverFilteredClient, error) { 359 mockDF := &mock.Deliver{} 360 mockDF.SendStub = func(*cb.Envelope) error { 361 <-delayChan 362 return nil 363 } 364 return mockDF, nil 365 } 366 return mockDC 367 } 368 369 func getMockDeliverClientRespondAfterDelay(delayChan chan struct{}, txStatus pb.TxValidationCode, txID string) *mock.PeerDeliverClient { 370 mockDC := &mock.PeerDeliverClient{} 371 mockDC.DeliverFilteredStub = func(ctx context.Context, opts ...grpc.CallOption) (pb.Deliver_DeliverFilteredClient, error) { 372 mockDF := &mock.Deliver{} 373 mockDF.RecvStub = func() (*pb.DeliverResponse, error) { 374 <-delayChan 375 resp := &pb.DeliverResponse{ 376 Type: &pb.DeliverResponse_FilteredBlock{ 377 FilteredBlock: createFilteredBlock(txStatus, txID), 378 }, 379 } 380 return resp, nil 381 } 382 return mockDF, nil 383 } 384 return mockDC 385 } 386 387 func getMockDeliverClientWithErr(errMsg string) *mock.PeerDeliverClient { 388 mockDC := &mock.PeerDeliverClient{} 389 mockDC.DeliverFilteredStub = func(ctx context.Context, opts ...grpc.CallOption) (pb.Deliver_DeliverFilteredClient, error) { 390 return nil, fmt.Errorf(errMsg) 391 } 392 return mockDC 393 } 394 395 func createFilteredBlock(txStatus pb.TxValidationCode, txIDs ...string) *pb.FilteredBlock { 396 var filteredTransactions []*pb.FilteredTransaction 397 for _, txID := range txIDs { 398 ft := &pb.FilteredTransaction{ 399 Txid: txID, 400 TxValidationCode: txStatus, 401 } 402 filteredTransactions = append(filteredTransactions, ft) 403 } 404 fb := &pb.FilteredBlock{ 405 Number: 0, 406 ChannelId: "testchannel", 407 FilteredTransactions: filteredTransactions, 408 } 409 return fb 410 }