github.com/anjalikarhana/fabric@v2.1.1+incompatible/internal/peer/lifecycle/chaincode/checkcommitreadiness_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("CheckCommitReadiness", func() {
    28  	Describe("CommitReadinessChecker", func() {
    29  		var (
    30  			mockProposalResponse   *pb.ProposalResponse
    31  			mockEndorserClient     *mock.EndorserClient
    32  			mockSigner             *mock.Signer
    33  			input                  *chaincode.CommitReadinessCheckInput
    34  			commitReadinessChecker *chaincode.CommitReadinessChecker
    35  		)
    36  
    37  		BeforeEach(func() {
    38  			mockEndorserClient = &mock.EndorserClient{}
    39  			mockResult := &lb.CheckCommitReadinessResult{
    40  				Approvals: map[string]bool{
    41  					"seemsfinetome":  true,
    42  					"well...ok":      true,
    43  					"absolutely-not": false,
    44  				},
    45  			}
    46  			mockResultBytes, err := proto.Marshal(mockResult)
    47  			Expect(err).NotTo(HaveOccurred())
    48  			Expect(mockResultBytes).NotTo(BeNil())
    49  			mockProposalResponse = &pb.ProposalResponse{
    50  				Response: &pb.Response{
    51  					Status:  200,
    52  					Payload: mockResultBytes,
    53  				},
    54  				Endorsement: &pb.Endorsement{},
    55  			}
    56  			mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil)
    57  
    58  			input = &chaincode.CommitReadinessCheckInput{
    59  				ChannelID: "testchannel",
    60  				Name:      "testcc",
    61  				Version:   "1.0",
    62  				Sequence:  1,
    63  			}
    64  
    65  			mockSigner = &mock.Signer{}
    66  			buffer := gbytes.NewBuffer()
    67  
    68  			commitReadinessChecker = &chaincode.CommitReadinessChecker{
    69  				Input:          input,
    70  				EndorserClient: mockEndorserClient,
    71  				Signer:         mockSigner,
    72  				Writer:         buffer,
    73  			}
    74  		})
    75  
    76  		It("checks whether a chaincode definition is ready to commit and writes the output as human readable plain-text", func() {
    77  			err := commitReadinessChecker.ReadinessCheck()
    78  			Expect(err).NotTo(HaveOccurred())
    79  			Eventually(commitReadinessChecker.Writer).Should(gbytes.Say("Chaincode definition for chaincode 'testcc', version '1.0', sequence '1' on channel 'testchannel' approval status by org"))
    80  			Eventually(commitReadinessChecker.Writer).Should(gbytes.Say("absolutely-not: false"))
    81  			Eventually(commitReadinessChecker.Writer).Should(gbytes.Say("seemsfinetome: true"))
    82  			Eventually(commitReadinessChecker.Writer).Should(gbytes.Say("well...ok: true"))
    83  		})
    84  
    85  		Context("when JSON-formatted output is requested", func() {
    86  			BeforeEach(func() {
    87  				commitReadinessChecker.Input.OutputFormat = "json"
    88  			})
    89  
    90  			It("checks whether a chaincode definition is ready to commit and writes the output as JSON", func() {
    91  				err := commitReadinessChecker.ReadinessCheck()
    92  				Expect(err).NotTo(HaveOccurred())
    93  				expectedOutput := &lb.CheckCommitReadinessResult{
    94  					Approvals: map[string]bool{
    95  						"absolutely-not": false,
    96  						"well...ok":      true,
    97  						"seemsfinetome":  true,
    98  					},
    99  				}
   100  				json, err := json.MarshalIndent(expectedOutput, "", "\t")
   101  				Eventually(commitReadinessChecker.Writer).Should(gbytes.Say(fmt.Sprintf("%s", string(json))))
   102  			})
   103  		})
   104  
   105  		Context("when the channel name is not provided", func() {
   106  			BeforeEach(func() {
   107  				commitReadinessChecker.Input.ChannelID = ""
   108  			})
   109  
   110  			It("returns an error", func() {
   111  				err := commitReadinessChecker.ReadinessCheck()
   112  				Expect(err).To(MatchError("The required parameter 'channelID' is empty. Rerun the command with -C flag"))
   113  			})
   114  		})
   115  
   116  		Context("when the chaincode name is not provided", func() {
   117  			BeforeEach(func() {
   118  				commitReadinessChecker.Input.Name = ""
   119  			})
   120  
   121  			It("returns an error", func() {
   122  				err := commitReadinessChecker.ReadinessCheck()
   123  				Expect(err).To(MatchError("The required parameter 'name' is empty. Rerun the command with -n flag"))
   124  			})
   125  		})
   126  
   127  		Context("when the chaincode version is not provided", func() {
   128  			BeforeEach(func() {
   129  				commitReadinessChecker.Input.Version = ""
   130  			})
   131  
   132  			It("returns an error", func() {
   133  				err := commitReadinessChecker.ReadinessCheck()
   134  				Expect(err).To(MatchError("The required parameter 'version' is empty. Rerun the command with -v flag"))
   135  			})
   136  		})
   137  
   138  		Context("when the sequence is not provided", func() {
   139  			BeforeEach(func() {
   140  				commitReadinessChecker.Input.Sequence = 0
   141  			})
   142  
   143  			It("returns an error", func() {
   144  				err := commitReadinessChecker.ReadinessCheck()
   145  				Expect(err).To(MatchError("The required parameter 'sequence' is empty. Rerun the command with --sequence flag"))
   146  			})
   147  		})
   148  
   149  		Context("when the signer cannot be serialized", func() {
   150  			BeforeEach(func() {
   151  				mockSigner.SerializeReturns(nil, errors.New("cafe"))
   152  			})
   153  
   154  			It("returns an error", func() {
   155  				err := commitReadinessChecker.ReadinessCheck()
   156  				Expect(err).To(MatchError("failed to create proposal: failed to serialize identity: cafe"))
   157  			})
   158  		})
   159  
   160  		Context("when the signer fails to sign the proposal", func() {
   161  			BeforeEach(func() {
   162  				mockSigner.SignReturns(nil, errors.New("tea"))
   163  			})
   164  
   165  			It("returns an error", func() {
   166  				err := commitReadinessChecker.ReadinessCheck()
   167  				Expect(err).To(MatchError("failed to create signed proposal: tea"))
   168  			})
   169  		})
   170  
   171  		Context("when the endorser fails to endorse the proposal", func() {
   172  			BeforeEach(func() {
   173  				mockEndorserClient.ProcessProposalReturns(nil, errors.New("latte"))
   174  			})
   175  
   176  			It("returns an error", func() {
   177  				err := commitReadinessChecker.ReadinessCheck()
   178  				Expect(err).To(MatchError("failed to endorse proposal: latte"))
   179  			})
   180  		})
   181  
   182  		Context("when the endorser returns a nil proposal response", func() {
   183  			BeforeEach(func() {
   184  				mockProposalResponse = nil
   185  				mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil)
   186  			})
   187  
   188  			It("returns an error", func() {
   189  				err := commitReadinessChecker.ReadinessCheck()
   190  				Expect(err).To(MatchError("received nil proposal response"))
   191  			})
   192  		})
   193  
   194  		Context("when the endorser returns a proposal response with a nil response", func() {
   195  			BeforeEach(func() {
   196  				mockProposalResponse.Response = nil
   197  				mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil)
   198  			})
   199  
   200  			It("returns an error", func() {
   201  				err := commitReadinessChecker.ReadinessCheck()
   202  				Expect(err).To(MatchError("received proposal response with nil response"))
   203  			})
   204  		})
   205  
   206  		Context("when the endorser returns a non-success status", func() {
   207  			BeforeEach(func() {
   208  				mockProposalResponse.Response = &pb.Response{
   209  					Status:  500,
   210  					Message: "capuccino",
   211  				}
   212  				mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil)
   213  			})
   214  
   215  			It("returns an error", func() {
   216  				err := commitReadinessChecker.ReadinessCheck()
   217  				Expect(err).To(MatchError("query failed with status: 500 - capuccino"))
   218  			})
   219  		})
   220  
   221  		Context("when the endorser returns an unexpected result", func() {
   222  			BeforeEach(func() {
   223  				mockProposalResponse.Response = &pb.Response{
   224  					Status:  200,
   225  					Payload: []byte("jibberish"),
   226  				}
   227  				mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil)
   228  			})
   229  
   230  			It("returns an error", func() {
   231  				err := commitReadinessChecker.ReadinessCheck()
   232  				Expect(err).To(MatchError(ContainSubstring("failed to unmarshal proposal response's response payload")))
   233  			})
   234  		})
   235  	})
   236  
   237  	Describe("CheckCommitReadinessCmd", func() {
   238  		var (
   239  			checkCommitReadinessCmd *cobra.Command
   240  		)
   241  
   242  		BeforeEach(func() {
   243  			cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   244  			Expect(err).To(BeNil())
   245  			checkCommitReadinessCmd = chaincode.CheckCommitReadinessCmd(nil, cryptoProvider)
   246  			checkCommitReadinessCmd.SetArgs([]string{
   247  				"--channelID=testchannel",
   248  				"--name=testcc",
   249  				"--version=testversion",
   250  				"--sequence=1",
   251  				"--peerAddresses=querypeer1",
   252  				"--tlsRootCertFiles=tls1",
   253  				"--signature-policy=AND ('Org1MSP.member','Org2MSP.member')",
   254  			})
   255  		})
   256  
   257  		AfterEach(func() {
   258  			chaincode.ResetFlags()
   259  		})
   260  
   261  		It("sets up the commit readiness checker and checks whether the chaincode definition is ready to commit", func() {
   262  			err := checkCommitReadinessCmd.Execute()
   263  			Expect(err).To(MatchError(ContainSubstring("failed to retrieve endorser client")))
   264  		})
   265  
   266  		Context("when the policy is invalid", func() {
   267  			BeforeEach(func() {
   268  				checkCommitReadinessCmd.SetArgs([]string{
   269  					"--signature-policy=notapolicy",
   270  					"--channelID=testchannel",
   271  					"--name=testcc",
   272  					"--version=testversion",
   273  					"--sequence=1",
   274  					"--peerAddresses=querypeer1",
   275  					"--tlsRootCertFiles=tls1",
   276  				})
   277  			})
   278  
   279  			It("returns an error", func() {
   280  				err := checkCommitReadinessCmd.Execute()
   281  				Expect(err).To(MatchError("invalid signature policy: notapolicy"))
   282  			})
   283  		})
   284  
   285  		Context("when the collections config is invalid", func() {
   286  			BeforeEach(func() {
   287  				checkCommitReadinessCmd.SetArgs([]string{
   288  					"--collections-config=idontexist.json",
   289  					"--channelID=testchannel",
   290  					"--name=testcc",
   291  					"--version=testversion",
   292  					"--sequence=1",
   293  					"--peerAddresses=querypeer1",
   294  					"--tlsRootCertFiles=tls1",
   295  				})
   296  			})
   297  
   298  			It("returns an error", func() {
   299  				err := checkCommitReadinessCmd.Execute()
   300  				Expect(err).To(MatchError("invalid collection configuration in file idontexist.json: could not read file 'idontexist.json': open idontexist.json: no such file or directory"))
   301  			})
   302  		})
   303  	})
   304  })