github.com/anjalikarhana/fabric@v2.1.1+incompatible/internal/peer/lifecycle/chaincode/querycommitted_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package chaincode_test
     8  
     9  import (
    10  	"encoding/json"
    11  	"fmt"
    12  
    13  	"github.com/golang/protobuf/proto"
    14  	pb "github.com/hyperledger/fabric-protos-go/peer"
    15  	lb "github.com/hyperledger/fabric-protos-go/peer/lifecycle"
    16  	"github.com/hyperledger/fabric/bccsp/sw"
    17  	"github.com/hyperledger/fabric/internal/peer/lifecycle/chaincode"
    18  	"github.com/hyperledger/fabric/internal/peer/lifecycle/chaincode/mock"
    19  	"github.com/pkg/errors"
    20  	"github.com/spf13/cobra"
    21  
    22  	. "github.com/onsi/ginkgo"
    23  	. "github.com/onsi/gomega"
    24  	"github.com/onsi/gomega/gbytes"
    25  )
    26  
    27  var _ = Describe("QueryCommitted", func() {
    28  	Describe("CommittedQuerier", func() {
    29  		var (
    30  			mockProposalResponse *pb.ProposalResponse
    31  			mockEndorserClient   *mock.EndorserClient
    32  			mockSigner           *mock.Signer
    33  			input                *chaincode.CommittedQueryInput
    34  			committedQuerier     *chaincode.CommittedQuerier
    35  		)
    36  
    37  		BeforeEach(func() {
    38  			mockResult := &lb.QueryChaincodeDefinitionsResult{
    39  				ChaincodeDefinitions: []*lb.QueryChaincodeDefinitionsResult_ChaincodeDefinition{
    40  					{
    41  						Name:              "woohoo",
    42  						Sequence:          93,
    43  						Version:           "a-version",
    44  						EndorsementPlugin: "e-plugin",
    45  						ValidationPlugin:  "v-plugin",
    46  					},
    47  					{
    48  						Name:              "yahoo",
    49  						Sequence:          20,
    50  						Version:           "another-version",
    51  						EndorsementPlugin: "e-plugin",
    52  						ValidationPlugin:  "v-plugin",
    53  					},
    54  				},
    55  			}
    56  
    57  			mockResultBytes, err := proto.Marshal(mockResult)
    58  			Expect(err).NotTo(HaveOccurred())
    59  			Expect(mockResultBytes).NotTo(BeNil())
    60  			mockProposalResponse = &pb.ProposalResponse{
    61  				Response: &pb.Response{
    62  					Status:  200,
    63  					Payload: mockResultBytes,
    64  				},
    65  			}
    66  
    67  			mockEndorserClient = &mock.EndorserClient{}
    68  			mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil)
    69  
    70  			mockSigner = &mock.Signer{}
    71  			buffer := gbytes.NewBuffer()
    72  
    73  			input = &chaincode.CommittedQueryInput{
    74  				ChannelID: "test-channel",
    75  			}
    76  
    77  			committedQuerier = &chaincode.CommittedQuerier{
    78  				Input:          input,
    79  				EndorserClient: mockEndorserClient,
    80  				Signer:         mockSigner,
    81  				Writer:         buffer,
    82  			}
    83  		})
    84  
    85  		It("queries committed chaincodes and writes the output as human readable plain-text", func() {
    86  			err := committedQuerier.Query()
    87  			Expect(err).NotTo(HaveOccurred())
    88  			Eventually(committedQuerier.Writer).Should(gbytes.Say("Committed chaincode definitions on channel 'test-channel':\n"))
    89  			Eventually(committedQuerier.Writer).Should(gbytes.Say("Name: woohoo, Version: a-version, Sequence: 93, Endorsement Plugin: e-plugin, Validation Plugin: v-plugin\n"))
    90  			Eventually(committedQuerier.Writer).Should(gbytes.Say("Name: yahoo, Version: another-version, Sequence: 20, Endorsement Plugin: e-plugin, Validation Plugin: v-plugin\n"))
    91  		})
    92  
    93  		Context("when JSON-formatted output is requested", func() {
    94  			BeforeEach(func() {
    95  				committedQuerier.Input.OutputFormat = "json"
    96  			})
    97  
    98  			It("queries committed chaincodes and writes the output as JSON", func() {
    99  				err := committedQuerier.Query()
   100  				Expect(err).NotTo(HaveOccurred())
   101  				expectedOutput := &lb.QueryChaincodeDefinitionsResult{
   102  					ChaincodeDefinitions: []*lb.QueryChaincodeDefinitionsResult_ChaincodeDefinition{
   103  						{
   104  							Name:              "woohoo",
   105  							Sequence:          93,
   106  							Version:           "a-version",
   107  							EndorsementPlugin: "e-plugin",
   108  							ValidationPlugin:  "v-plugin",
   109  						},
   110  						{
   111  							Name:              "yahoo",
   112  							Sequence:          20,
   113  							Version:           "another-version",
   114  							EndorsementPlugin: "e-plugin",
   115  							ValidationPlugin:  "v-plugin",
   116  						},
   117  					},
   118  				}
   119  				json, err := json.MarshalIndent(expectedOutput, "", "\t")
   120  				Eventually(committedQuerier.Writer).Should(gbytes.Say(fmt.Sprintf(`\Q%s\E`, string(json))))
   121  			})
   122  		})
   123  
   124  		Context("when a single chaincode definition is requested", func() {
   125  			BeforeEach(func() {
   126  				input.Name = "test-cc"
   127  
   128  				mockResult := &lb.QueryChaincodeDefinitionResult{
   129  					Sequence:          93,
   130  					Version:           "a-version",
   131  					EndorsementPlugin: "e-plugin",
   132  					ValidationPlugin:  "v-plugin",
   133  					Approvals: map[string]bool{
   134  						"whatkindoforgisthis": true,
   135  						"nowaydoiapprove":     false,
   136  					},
   137  				}
   138  
   139  				mockResultBytes, err := proto.Marshal(mockResult)
   140  				Expect(err).NotTo(HaveOccurred())
   141  				Expect(mockResultBytes).NotTo(BeNil())
   142  				mockProposalResponse = &pb.ProposalResponse{
   143  					Response: &pb.Response{
   144  						Status:  200,
   145  						Payload: mockResultBytes,
   146  					},
   147  				}
   148  
   149  				mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil)
   150  			})
   151  
   152  			It("queries the committed chaincode and writes the output as human readable plain-text", func() {
   153  				err := committedQuerier.Query()
   154  				Expect(err).NotTo(HaveOccurred())
   155  				Eventually(committedQuerier.Writer).Should(gbytes.Say("Committed chaincode definition for chaincode 'test-cc' on channel 'test-channel'"))
   156  				Eventually(committedQuerier.Writer).Should(gbytes.Say(`\QVersion: a-version, Sequence: 93, Endorsement Plugin: e-plugin, Validation Plugin: v-plugin, Approvals: [nowaydoiapprove: false, whatkindoforgisthis: true]\E`))
   157  			})
   158  
   159  			Context("when the payload contains bytes that aren't a QueryChaincodeDefinitionResult", func() {
   160  				BeforeEach(func() {
   161  					mockProposalResponse.Response = &pb.Response{
   162  						Payload: []byte("badpayloadbadpayload"),
   163  						Status:  200,
   164  					}
   165  					mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil)
   166  				})
   167  
   168  				It("returns an error", func() {
   169  					err := committedQuerier.Query()
   170  					Expect(err).To(MatchError(ContainSubstring("failed to unmarshal proposal response's response payload")))
   171  				})
   172  			})
   173  
   174  			Context("when JSON-formatted output is requested", func() {
   175  				BeforeEach(func() {
   176  					committedQuerier.Input.OutputFormat = "json"
   177  				})
   178  
   179  				It("queries the committed chaincodes and writes the output as JSON", func() {
   180  					err := committedQuerier.Query()
   181  					Expect(err).NotTo(HaveOccurred())
   182  					expectedOutput := &lb.QueryChaincodeDefinitionResult{
   183  						Sequence:          93,
   184  						Version:           "a-version",
   185  						EndorsementPlugin: "e-plugin",
   186  						ValidationPlugin:  "v-plugin",
   187  						Approvals: map[string]bool{
   188  							"whatkindoforgisthis": true,
   189  							"nowaydoiapprove":     false,
   190  						},
   191  					}
   192  					json, err := json.MarshalIndent(expectedOutput, "", "\t")
   193  					Eventually(committedQuerier.Writer).Should(gbytes.Say(fmt.Sprintf(`\Q%s\E`, string(json))))
   194  				})
   195  			})
   196  		})
   197  
   198  		Context("when the channel is not provided", func() {
   199  			BeforeEach(func() {
   200  				committedQuerier.Input.ChannelID = ""
   201  			})
   202  
   203  			It("returns an error", func() {
   204  				err := committedQuerier.Query()
   205  				Expect(err).To(MatchError("channel name must be specified"))
   206  			})
   207  		})
   208  
   209  		Context("when the signer cannot be serialized", func() {
   210  			BeforeEach(func() {
   211  				mockSigner.SerializeReturns(nil, errors.New("cafe"))
   212  			})
   213  
   214  			It("returns an error", func() {
   215  				err := committedQuerier.Query()
   216  				Expect(err).To(MatchError("failed to create proposal: failed to serialize identity: cafe"))
   217  			})
   218  		})
   219  
   220  		Context("when the signer fails to sign the proposal", func() {
   221  			BeforeEach(func() {
   222  				mockSigner.SignReturns(nil, errors.New("tea"))
   223  			})
   224  
   225  			It("returns an error", func() {
   226  				err := committedQuerier.Query()
   227  				Expect(err).To(MatchError("failed to create signed proposal: tea"))
   228  			})
   229  		})
   230  
   231  		Context("when the endorser fails to endorse the proposal", func() {
   232  			BeforeEach(func() {
   233  				mockEndorserClient.ProcessProposalReturns(nil, errors.New("latte"))
   234  			})
   235  
   236  			It("returns an error", func() {
   237  				err := committedQuerier.Query()
   238  				Expect(err).To(MatchError("failed to endorse proposal: latte"))
   239  			})
   240  		})
   241  
   242  		Context("when the endorser returns a nil proposal response", func() {
   243  			BeforeEach(func() {
   244  				mockProposalResponse = nil
   245  				mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil)
   246  			})
   247  
   248  			It("returns an error", func() {
   249  				err := committedQuerier.Query()
   250  				Expect(err).To(MatchError("received nil proposal response"))
   251  			})
   252  		})
   253  
   254  		Context("when the endorser returns a proposal response with a nil response", func() {
   255  			BeforeEach(func() {
   256  				mockProposalResponse.Response = nil
   257  				mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil)
   258  			})
   259  
   260  			It("returns an error", func() {
   261  				err := committedQuerier.Query()
   262  				Expect(err).To(MatchError("received proposal response with nil response"))
   263  			})
   264  		})
   265  
   266  		Context("when the endorser returns a non-success status", func() {
   267  			BeforeEach(func() {
   268  				mockProposalResponse.Response = &pb.Response{
   269  					Status:  500,
   270  					Message: "capuccino",
   271  				}
   272  				mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil)
   273  			})
   274  
   275  			It("returns an error", func() {
   276  				err := committedQuerier.Query()
   277  				Expect(err).To(MatchError("query failed with status: 500 - capuccino"))
   278  			})
   279  		})
   280  
   281  		Context("when the payload contains bytes that aren't a QueryChaincodeDefinitionsResult", func() {
   282  			BeforeEach(func() {
   283  				mockProposalResponse.Response = &pb.Response{
   284  					Payload: []byte("badpayloadbadpayload"),
   285  					Status:  200,
   286  				}
   287  				mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil)
   288  			})
   289  
   290  			It("returns an error", func() {
   291  				err := committedQuerier.Query()
   292  				Expect(err).To(MatchError(ContainSubstring("failed to unmarshal proposal response's response payload")))
   293  			})
   294  		})
   295  
   296  		Context("when the payload contains bytes that aren't a QueryChaincodeDefinitionsResult and JSON-output is requested", func() {
   297  			BeforeEach(func() {
   298  				mockProposalResponse.Response = &pb.Response{
   299  					Payload: []byte("badpayloadbadpayload"),
   300  					Status:  200,
   301  				}
   302  				mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil)
   303  				committedQuerier.Input.OutputFormat = "json"
   304  			})
   305  
   306  			It("returns an error", func() {
   307  				err := committedQuerier.Query()
   308  				Expect(err).To(MatchError(ContainSubstring("failed to unmarshal proposal response's response payload as type *lifecycle.QueryChaincodeDefinitionsResult")))
   309  			})
   310  		})
   311  	})
   312  
   313  	Describe("QueryCommittedCmd", func() {
   314  		var (
   315  			queryCommittedCmd *cobra.Command
   316  		)
   317  
   318  		BeforeEach(func() {
   319  			cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   320  			Expect(err).To(BeNil())
   321  			queryCommittedCmd = chaincode.QueryCommittedCmd(nil, cryptoProvider)
   322  			queryCommittedCmd.SetArgs([]string{
   323  				"--name=testcc",
   324  				"--channelID=testchannel",
   325  				"--peerAddresses=querycommittedpeer1",
   326  				"--tlsRootCertFiles=tls1",
   327  			})
   328  		})
   329  
   330  		AfterEach(func() {
   331  			chaincode.ResetFlags()
   332  		})
   333  
   334  		It("attempts to connect to the endorser", func() {
   335  			err := queryCommittedCmd.Execute()
   336  			Expect(err).To(MatchError(ContainSubstring("failed to retrieve endorser client")))
   337  		})
   338  
   339  		Context("when more than one peer address is provided", func() {
   340  			BeforeEach(func() {
   341  				queryCommittedCmd.SetArgs([]string{
   342  					"--name=testcc",
   343  					"--channelID=testchannel",
   344  					"--peerAddresses=querycommittedpeer1",
   345  					"--tlsRootCertFiles=tls1",
   346  					"--peerAddresses=querycommittedpeer2",
   347  					"--tlsRootCertFiles=tls2",
   348  				})
   349  			})
   350  
   351  			It("returns an error", func() {
   352  				err := queryCommittedCmd.Execute()
   353  				Expect(err).To(MatchError(ContainSubstring("failed to validate peer connection parameters")))
   354  			})
   355  		})
   356  	})
   357  })