github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/internal/peer/lifecycle/chaincode/queryapproved_test.go (about) 1 /* 2 Copyright Hitachi America, Ltd. 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 "github.com/hechain20/hechain/bccsp/sw" 15 "github.com/hechain20/hechain/internal/peer/lifecycle/chaincode" 16 "github.com/hechain20/hechain/internal/peer/lifecycle/chaincode/mock" 17 pb "github.com/hyperledger/fabric-protos-go/peer" 18 lb "github.com/hyperledger/fabric-protos-go/peer/lifecycle" 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("QueryApproved", func() { 28 Describe("ApprovedQuerier", func() { 29 var ( 30 mockProposalResponse *pb.ProposalResponse 31 mockEndorserClient *mock.EndorserClient 32 mockSigner *mock.Signer 33 input *chaincode.ApprovedQueryInput 34 approvedQuerier *chaincode.ApprovedQuerier 35 ) 36 37 BeforeEach(func() { 38 mockResult := &lb.QueryApprovedChaincodeDefinitionResult{ 39 Sequence: 7, 40 Version: "version_1.0", 41 EndorsementPlugin: "endorsement-plugin", 42 ValidationPlugin: "validation-plugin", 43 ValidationParameter: []byte("validation-parameter"), 44 InitRequired: true, 45 Collections: &pb.CollectionConfigPackage{}, 46 Source: &lb.ChaincodeSource{ 47 Type: &lb.ChaincodeSource_LocalPackage{ 48 LocalPackage: &lb.ChaincodeSource_Local{ 49 PackageId: "hash", 50 }, 51 }, 52 }, 53 } 54 55 mockResultBytes, err := proto.Marshal(mockResult) 56 Expect(err).NotTo(HaveOccurred()) 57 Expect(mockResultBytes).NotTo(BeNil()) 58 mockProposalResponse = &pb.ProposalResponse{ 59 Response: &pb.Response{ 60 Status: 200, 61 Payload: mockResultBytes, 62 }, 63 } 64 65 mockEndorserClient = &mock.EndorserClient{} 66 mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil) 67 68 mockSigner = &mock.Signer{} 69 buffer := gbytes.NewBuffer() 70 71 input = &chaincode.ApprovedQueryInput{ 72 ChannelID: "test-channel", 73 Name: "cc_name", 74 } 75 76 approvedQuerier = &chaincode.ApprovedQuerier{ 77 Input: input, 78 EndorserClient: mockEndorserClient, 79 Signer: mockSigner, 80 Writer: buffer, 81 } 82 }) 83 84 It("queries a approved chaincode and writes the output as human readable plain-text", func() { 85 err := approvedQuerier.Query() 86 Expect(err).NotTo(HaveOccurred()) 87 Eventually(approvedQuerier.Writer).Should(gbytes.Say("Approved chaincode definition for chaincode 'cc_name' on channel 'test-channel':\n")) 88 Eventually(approvedQuerier.Writer).Should(gbytes.Say("sequence: 7, version: version_1.0, init-required: true, package-id: hash, endorsement plugin: endorsement-plugin, validation plugin: validation-plugin\n")) 89 }) 90 91 Context("when the payload contains bytes that aren't a QueryApprovedChaincodeDefinitionResult", func() { 92 BeforeEach(func() { 93 mockProposalResponse.Response = &pb.Response{ 94 Payload: []byte("badpayloadbadpayload"), 95 Status: 200, 96 } 97 mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil) 98 }) 99 100 It("returns an error", func() { 101 err := approvedQuerier.Query() 102 Expect(err).To(MatchError(ContainSubstring("failed to unmarshal proposal response's response payload"))) 103 }) 104 }) 105 106 Context("when JSON-formatted output is requested", func() { 107 BeforeEach(func() { 108 approvedQuerier.Input.OutputFormat = "json" 109 }) 110 111 It("queries the approved chaincode and writes the output as JSON", func() { 112 err := approvedQuerier.Query() 113 Expect(err).NotTo(HaveOccurred()) 114 expectedOutput := &lb.QueryApprovedChaincodeDefinitionResult{ 115 Sequence: 7, 116 Version: "version_1.0", 117 EndorsementPlugin: "endorsement-plugin", 118 ValidationPlugin: "validation-plugin", 119 ValidationParameter: []byte("validation-parameter"), 120 InitRequired: true, 121 Collections: &pb.CollectionConfigPackage{}, 122 Source: &lb.ChaincodeSource{ 123 Type: &lb.ChaincodeSource_LocalPackage{ 124 LocalPackage: &lb.ChaincodeSource_Local{ 125 PackageId: "hash", 126 }, 127 }, 128 }, 129 } 130 json, err := json.MarshalIndent(expectedOutput, "", "\t") 131 Expect(err).NotTo(HaveOccurred()) 132 Eventually(approvedQuerier.Writer).Should(gbytes.Say(fmt.Sprintf(`\Q%s\E`, string(json)))) 133 }) 134 }) 135 136 Context("when the chaincode source is unavailable", func() { 137 BeforeEach(func() { 138 mockResult := &lb.QueryApprovedChaincodeDefinitionResult{ 139 Sequence: 7, 140 Version: "version_1.0", 141 EndorsementPlugin: "endorsement-plugin", 142 ValidationPlugin: "validation-plugin", 143 ValidationParameter: []byte("validation-parameter"), 144 InitRequired: true, 145 Collections: &pb.CollectionConfigPackage{}, 146 Source: &lb.ChaincodeSource{ 147 Type: &lb.ChaincodeSource_Unavailable_{ 148 Unavailable: &lb.ChaincodeSource_Unavailable{}, 149 }, 150 }, 151 } 152 mockResultBytes, err := proto.Marshal(mockResult) 153 Expect(err).NotTo(HaveOccurred()) 154 Expect(mockResultBytes).NotTo(BeNil()) 155 156 mockProposalResponse = &pb.ProposalResponse{ 157 Response: &pb.Response{ 158 Status: 200, 159 Payload: mockResultBytes, 160 }, 161 } 162 mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil) 163 }) 164 165 It("queries the approved chaincode and writes the output as human readable plain-text with an empty package-id", func() { 166 err := approvedQuerier.Query() 167 Expect(err).NotTo(HaveOccurred()) 168 Eventually(approvedQuerier.Writer).Should(gbytes.Say("Approved chaincode definition for chaincode 'cc_name' on channel 'test-channel':\n")) 169 Eventually(approvedQuerier.Writer).Should(gbytes.Say("sequence: 7, version: version_1.0, init-required: true, package-id: , endorsement plugin: endorsement-plugin, validation plugin: validation-plugin\n")) 170 }) 171 }) 172 173 Context("when the channel is not provided", func() { 174 BeforeEach(func() { 175 approvedQuerier.Input.ChannelID = "" 176 }) 177 178 It("returns an error", func() { 179 err := approvedQuerier.Query() 180 Expect(err).To(MatchError("The required parameter 'channelID' is empty. Rerun the command with -C flag")) 181 }) 182 }) 183 184 Context("when the chaincode name is not provided", func() { 185 BeforeEach(func() { 186 approvedQuerier.Input.Name = "" 187 }) 188 189 It("returns an error", func() { 190 err := approvedQuerier.Query() 191 Expect(err).To(MatchError("The required parameter 'name' is empty. Rerun the command with -n flag")) 192 }) 193 }) 194 195 Context("when the signer cannot be serialized", func() { 196 BeforeEach(func() { 197 mockSigner.SerializeReturns(nil, errors.New("bad serialization")) 198 }) 199 200 It("returns an error", func() { 201 err := approvedQuerier.Query() 202 Expect(err).To(MatchError("failed to create proposal: failed to serialize identity: bad serialization")) 203 }) 204 }) 205 206 Context("when the signer fails to sign the proposal", func() { 207 BeforeEach(func() { 208 mockSigner.SignReturns(nil, errors.New("bad sign")) 209 }) 210 211 It("returns an error", func() { 212 err := approvedQuerier.Query() 213 Expect(err).To(MatchError("failed to create signed proposal: bad sign")) 214 }) 215 }) 216 217 Context("when the endorser fails to endorse the proposal", func() { 218 BeforeEach(func() { 219 mockEndorserClient.ProcessProposalReturns(nil, errors.New("bad endorsement")) 220 }) 221 222 It("returns an error", func() { 223 err := approvedQuerier.Query() 224 Expect(err).To(MatchError("failed to endorse proposal: bad endorsement")) 225 }) 226 }) 227 228 Context("when the endorser returns a nil proposal response", func() { 229 BeforeEach(func() { 230 mockProposalResponse = nil 231 mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil) 232 }) 233 234 It("returns an error", func() { 235 err := approvedQuerier.Query() 236 Expect(err).To(MatchError("received nil proposal response")) 237 }) 238 }) 239 240 Context("when the endorser returns a proposal response with a nil response", func() { 241 BeforeEach(func() { 242 mockProposalResponse.Response = nil 243 mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil) 244 }) 245 246 It("returns an error", func() { 247 err := approvedQuerier.Query() 248 Expect(err).To(MatchError("received proposal response with nil response")) 249 }) 250 }) 251 252 Context("when the endorser returns a non-success status", func() { 253 BeforeEach(func() { 254 mockProposalResponse.Response = &pb.Response{ 255 Status: 500, 256 Message: "message", 257 } 258 mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil) 259 }) 260 261 It("returns an error", func() { 262 err := approvedQuerier.Query() 263 Expect(err).To(MatchError("query failed with status: 500 - message")) 264 }) 265 }) 266 }) 267 268 Describe("QueryApprovedCmd", func() { 269 var queryApprovedCmd *cobra.Command 270 271 BeforeEach(func() { 272 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 273 Expect(err).To(BeNil()) 274 queryApprovedCmd = chaincode.QueryApprovedCmd(nil, cryptoProvider) 275 queryApprovedCmd.SilenceErrors = true 276 queryApprovedCmd.SilenceUsage = true 277 queryApprovedCmd.SetArgs([]string{ 278 "--name=testcc", 279 "--channelID=testchannel", 280 "--peerAddresses=queryapprovedpeer1", 281 "--tlsRootCertFiles=tls1", 282 }) 283 }) 284 285 AfterEach(func() { 286 chaincode.ResetFlags() 287 }) 288 289 It("attempts to connect to the endorser", func() { 290 err := queryApprovedCmd.Execute() 291 Expect(err).To(MatchError(ContainSubstring("failed to retrieve endorser client"))) 292 }) 293 294 Context("when more than one peer address is provided", func() { 295 BeforeEach(func() { 296 queryApprovedCmd.SetArgs([]string{ 297 "--name=testcc", 298 "--channelID=testchannel", 299 "--peerAddresses=queryapprovedpeer1", 300 "--tlsRootCertFiles=tls1", 301 "--peerAddresses=queryapprovedpeer2", 302 "--tlsRootCertFiles=tls2", 303 }) 304 }) 305 306 It("returns an error", func() { 307 err := queryApprovedCmd.Execute() 308 Expect(err).To(MatchError(ContainSubstring("failed to validate peer connection parameters"))) 309 }) 310 }) 311 }) 312 })