github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/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/osdi23p228/fabric/bccsp/sw"
    17  	"github.com/osdi23p228/fabric/internal/peer/lifecycle/chaincode"
    18  	"github.com/osdi23p228/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  				Expect(err).NotTo(HaveOccurred())
   121  				Eventually(committedQuerier.Writer).Should(gbytes.Say(fmt.Sprintf(`\Q%s\E`, string(json))))
   122  			})
   123  		})
   124  
   125  		Context("when a single chaincode definition is requested", func() {
   126  			BeforeEach(func() {
   127  				input.Name = "test-cc"
   128  
   129  				mockResult := &lb.QueryChaincodeDefinitionResult{
   130  					Sequence:          93,
   131  					Version:           "a-version",
   132  					EndorsementPlugin: "e-plugin",
   133  					ValidationPlugin:  "v-plugin",
   134  					Approvals: map[string]bool{
   135  						"whatkindoforgisthis": true,
   136  						"nowaydoiapprove":     false,
   137  					},
   138  				}
   139  
   140  				mockResultBytes, err := proto.Marshal(mockResult)
   141  				Expect(err).NotTo(HaveOccurred())
   142  				Expect(mockResultBytes).NotTo(BeNil())
   143  				mockProposalResponse = &pb.ProposalResponse{
   144  					Response: &pb.Response{
   145  						Status:  200,
   146  						Payload: mockResultBytes,
   147  					},
   148  				}
   149  
   150  				mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil)
   151  			})
   152  
   153  			It("queries the committed chaincode and writes the output as human readable plain-text", func() {
   154  				err := committedQuerier.Query()
   155  				Expect(err).NotTo(HaveOccurred())
   156  				Eventually(committedQuerier.Writer).Should(gbytes.Say("Committed chaincode definition for chaincode 'test-cc' on channel 'test-channel'"))
   157  				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`))
   158  			})
   159  
   160  			Context("when the payload contains bytes that aren't a QueryChaincodeDefinitionResult", func() {
   161  				BeforeEach(func() {
   162  					mockProposalResponse.Response = &pb.Response{
   163  						Payload: []byte("badpayloadbadpayload"),
   164  						Status:  200,
   165  					}
   166  					mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil)
   167  				})
   168  
   169  				It("returns an error", func() {
   170  					err := committedQuerier.Query()
   171  					Expect(err).To(MatchError(ContainSubstring("failed to unmarshal proposal response's response payload")))
   172  				})
   173  			})
   174  
   175  			Context("when JSON-formatted output is requested", func() {
   176  				BeforeEach(func() {
   177  					committedQuerier.Input.OutputFormat = "json"
   178  				})
   179  
   180  				It("queries the committed chaincodes and writes the output as JSON", func() {
   181  					err := committedQuerier.Query()
   182  					Expect(err).NotTo(HaveOccurred())
   183  					expectedOutput := &lb.QueryChaincodeDefinitionResult{
   184  						Sequence:          93,
   185  						Version:           "a-version",
   186  						EndorsementPlugin: "e-plugin",
   187  						ValidationPlugin:  "v-plugin",
   188  						Approvals: map[string]bool{
   189  							"whatkindoforgisthis": true,
   190  							"nowaydoiapprove":     false,
   191  						},
   192  					}
   193  					json, err := json.MarshalIndent(expectedOutput, "", "\t")
   194  					Expect(err).NotTo(HaveOccurred())
   195  					Eventually(committedQuerier.Writer).Should(gbytes.Say(fmt.Sprintf(`\Q%s\E`, string(json))))
   196  				})
   197  			})
   198  		})
   199  
   200  		Context("when the channel is not provided", func() {
   201  			BeforeEach(func() {
   202  				committedQuerier.Input.ChannelID = ""
   203  			})
   204  
   205  			It("returns an error", func() {
   206  				err := committedQuerier.Query()
   207  				Expect(err).To(MatchError("channel name must be specified"))
   208  			})
   209  		})
   210  
   211  		Context("when the signer cannot be serialized", func() {
   212  			BeforeEach(func() {
   213  				mockSigner.SerializeReturns(nil, errors.New("cafe"))
   214  			})
   215  
   216  			It("returns an error", func() {
   217  				err := committedQuerier.Query()
   218  				Expect(err).To(MatchError("failed to create proposal: failed to serialize identity: cafe"))
   219  			})
   220  		})
   221  
   222  		Context("when the signer fails to sign the proposal", func() {
   223  			BeforeEach(func() {
   224  				mockSigner.SignReturns(nil, errors.New("tea"))
   225  			})
   226  
   227  			It("returns an error", func() {
   228  				err := committedQuerier.Query()
   229  				Expect(err).To(MatchError("failed to create signed proposal: tea"))
   230  			})
   231  		})
   232  
   233  		Context("when the endorser fails to endorse the proposal", func() {
   234  			BeforeEach(func() {
   235  				mockEndorserClient.ProcessProposalReturns(nil, errors.New("latte"))
   236  			})
   237  
   238  			It("returns an error", func() {
   239  				err := committedQuerier.Query()
   240  				Expect(err).To(MatchError("failed to endorse proposal: latte"))
   241  			})
   242  		})
   243  
   244  		Context("when the endorser returns a nil proposal response", func() {
   245  			BeforeEach(func() {
   246  				mockProposalResponse = nil
   247  				mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil)
   248  			})
   249  
   250  			It("returns an error", func() {
   251  				err := committedQuerier.Query()
   252  				Expect(err).To(MatchError("received nil proposal response"))
   253  			})
   254  		})
   255  
   256  		Context("when the endorser returns a proposal response with a nil response", func() {
   257  			BeforeEach(func() {
   258  				mockProposalResponse.Response = nil
   259  				mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil)
   260  			})
   261  
   262  			It("returns an error", func() {
   263  				err := committedQuerier.Query()
   264  				Expect(err).To(MatchError("received proposal response with nil response"))
   265  			})
   266  		})
   267  
   268  		Context("when the endorser returns a non-success status", func() {
   269  			BeforeEach(func() {
   270  				mockProposalResponse.Response = &pb.Response{
   271  					Status:  500,
   272  					Message: "capuccino",
   273  				}
   274  				mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil)
   275  			})
   276  
   277  			It("returns an error", func() {
   278  				err := committedQuerier.Query()
   279  				Expect(err).To(MatchError("query failed with status: 500 - capuccino"))
   280  			})
   281  		})
   282  
   283  		Context("when the payload contains bytes that aren't a QueryChaincodeDefinitionsResult", func() {
   284  			BeforeEach(func() {
   285  				mockProposalResponse.Response = &pb.Response{
   286  					Payload: []byte("badpayloadbadpayload"),
   287  					Status:  200,
   288  				}
   289  				mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil)
   290  			})
   291  
   292  			It("returns an error", func() {
   293  				err := committedQuerier.Query()
   294  				Expect(err).To(MatchError(ContainSubstring("failed to unmarshal proposal response's response payload")))
   295  			})
   296  		})
   297  
   298  		Context("when the payload contains bytes that aren't a QueryChaincodeDefinitionsResult and JSON-output is requested", func() {
   299  			BeforeEach(func() {
   300  				mockProposalResponse.Response = &pb.Response{
   301  					Payload: []byte("badpayloadbadpayload"),
   302  					Status:  200,
   303  				}
   304  				mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil)
   305  				committedQuerier.Input.OutputFormat = "json"
   306  			})
   307  
   308  			It("returns an error", func() {
   309  				err := committedQuerier.Query()
   310  				Expect(err).To(MatchError(ContainSubstring("failed to unmarshal proposal response's response payload as type *lifecycle.QueryChaincodeDefinitionsResult")))
   311  			})
   312  		})
   313  	})
   314  
   315  	Describe("QueryCommittedCmd", func() {
   316  		var queryCommittedCmd *cobra.Command
   317  
   318  		BeforeEach(func() {
   319  			cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   320  			Expect(err).To(BeNil())
   321  			queryCommittedCmd = chaincode.QueryCommittedCmd(nil, cryptoProvider)
   322  			queryCommittedCmd.SilenceErrors = true
   323  			queryCommittedCmd.SilenceUsage = true
   324  			queryCommittedCmd.SetArgs([]string{
   325  				"--name=testcc",
   326  				"--channelID=testchannel",
   327  				"--peerAddresses=querycommittedpeer1",
   328  				"--tlsRootCertFiles=tls1",
   329  			})
   330  		})
   331  
   332  		AfterEach(func() {
   333  			chaincode.ResetFlags()
   334  		})
   335  
   336  		It("attempts to connect to the endorser", func() {
   337  			err := queryCommittedCmd.Execute()
   338  			Expect(err).To(MatchError(ContainSubstring("failed to retrieve endorser client")))
   339  		})
   340  
   341  		Context("when more than one peer address is provided", func() {
   342  			BeforeEach(func() {
   343  				queryCommittedCmd.SetArgs([]string{
   344  					"--name=testcc",
   345  					"--channelID=testchannel",
   346  					"--peerAddresses=querycommittedpeer1",
   347  					"--tlsRootCertFiles=tls1",
   348  					"--peerAddresses=querycommittedpeer2",
   349  					"--tlsRootCertFiles=tls2",
   350  				})
   351  			})
   352  
   353  			It("returns an error", func() {
   354  				err := queryCommittedCmd.Execute()
   355  				Expect(err).To(MatchError(ContainSubstring("failed to validate peer connection parameters")))
   356  			})
   357  		})
   358  	})
   359  })