github.com/defanghe/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 })