github.com/defanghe/fabric@v2.1.1+incompatible/internal/peer/lifecycle/chaincode/commit_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 "context" 11 "crypto/tls" 12 "time" 13 14 pb "github.com/hyperledger/fabric-protos-go/peer" 15 "github.com/hyperledger/fabric/bccsp/sw" 16 "github.com/hyperledger/fabric/internal/peer/lifecycle/chaincode" 17 "github.com/hyperledger/fabric/internal/peer/lifecycle/chaincode/mock" 18 "github.com/pkg/errors" 19 "github.com/spf13/cobra" 20 "google.golang.org/grpc" 21 22 . "github.com/onsi/ginkgo" 23 . "github.com/onsi/gomega" 24 ) 25 26 var _ = Describe("Commit", func() { 27 Describe("Committer", func() { 28 var ( 29 mockProposalResponse *pb.ProposalResponse 30 mockEndorserClient *mock.EndorserClient 31 mockEndorserClients []chaincode.EndorserClient 32 mockDeliverClient *mock.PeerDeliverClient 33 mockSigner *mock.Signer 34 certificate tls.Certificate 35 mockBroadcastClient *mock.BroadcastClient 36 input *chaincode.CommitInput 37 committer *chaincode.Committer 38 ) 39 40 BeforeEach(func() { 41 mockEndorserClient = &mock.EndorserClient{} 42 43 mockProposalResponse = &pb.ProposalResponse{ 44 Response: &pb.Response{ 45 Status: 200, 46 }, 47 Endorsement: &pb.Endorsement{}, 48 } 49 mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil) 50 mockEndorserClients = []chaincode.EndorserClient{mockEndorserClient} 51 52 mockDeliverClient = &mock.PeerDeliverClient{} 53 input = &chaincode.CommitInput{ 54 ChannelID: "testchannel", 55 Name: "testcc", 56 Version: "1.0", 57 Sequence: 1, 58 } 59 60 mockSigner = &mock.Signer{} 61 62 certificate = tls.Certificate{} 63 mockBroadcastClient = &mock.BroadcastClient{} 64 65 committer = &chaincode.Committer{ 66 Certificate: certificate, 67 BroadcastClient: mockBroadcastClient, 68 DeliverClients: []pb.DeliverClient{mockDeliverClient}, 69 EndorserClients: mockEndorserClients, 70 Input: input, 71 Signer: mockSigner, 72 } 73 }) 74 75 It("commits a chaincode definition", func() { 76 err := committer.Commit() 77 Expect(err).NotTo(HaveOccurred()) 78 }) 79 80 Context("when the channel name is not provided", func() { 81 BeforeEach(func() { 82 committer.Input.ChannelID = "" 83 }) 84 85 It("returns an error", func() { 86 err := committer.Commit() 87 Expect(err).To(MatchError("The required parameter 'channelID' is empty. Rerun the command with -C flag")) 88 }) 89 }) 90 91 Context("when the chaincode name is not provided", func() { 92 BeforeEach(func() { 93 committer.Input.Name = "" 94 }) 95 96 It("returns an error", func() { 97 err := committer.Commit() 98 Expect(err).To(MatchError("The required parameter 'name' is empty. Rerun the command with -n flag")) 99 }) 100 }) 101 102 Context("when the chaincode version is not provided", func() { 103 BeforeEach(func() { 104 committer.Input.Version = "" 105 }) 106 107 It("returns an error", func() { 108 err := committer.Commit() 109 Expect(err).To(MatchError("The required parameter 'version' is empty. Rerun the command with -v flag")) 110 }) 111 }) 112 113 Context("when the sequence is not provided", func() { 114 BeforeEach(func() { 115 committer.Input.Sequence = 0 116 }) 117 118 It("returns an error", func() { 119 err := committer.Commit() 120 Expect(err).To(MatchError("The required parameter 'sequence' is empty. Rerun the command with --sequence flag")) 121 }) 122 }) 123 124 Context("when the signer cannot be serialized", func() { 125 BeforeEach(func() { 126 mockSigner.SerializeReturns(nil, errors.New("cafe")) 127 }) 128 129 It("returns an error", func() { 130 err := committer.Commit() 131 Expect(err).To(MatchError("failed to create proposal: failed to serialize identity: cafe")) 132 }) 133 }) 134 135 Context("when the signer fails to sign the proposal", func() { 136 BeforeEach(func() { 137 mockSigner.SignReturns(nil, errors.New("tea")) 138 }) 139 140 It("returns an error", func() { 141 err := committer.Commit() 142 Expect(err).To(MatchError("failed to create signed proposal: tea")) 143 }) 144 }) 145 146 Context("when the endorser fails to endorse the proposal", func() { 147 BeforeEach(func() { 148 mockEndorserClient.ProcessProposalReturns(nil, errors.New("latte")) 149 }) 150 151 It("returns an error", func() { 152 err := committer.Commit() 153 Expect(err).To(MatchError("failed to endorse proposal: latte")) 154 }) 155 }) 156 157 Context("when no endorser clients are set", func() { 158 BeforeEach(func() { 159 committer.EndorserClients = nil 160 }) 161 162 It("doesn't receive any responses and returns an error", func() { 163 err := committer.Commit() 164 Expect(err).To(MatchError("no proposal responses received")) 165 }) 166 }) 167 168 Context("when the endorser returns a nil proposal response", func() { 169 BeforeEach(func() { 170 mockProposalResponse = nil 171 mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil) 172 }) 173 174 It("returns an error", func() { 175 err := committer.Commit() 176 Expect(err).To(MatchError("received nil proposal response")) 177 }) 178 }) 179 180 Context("when the endorser returns a proposal response with a nil response", func() { 181 BeforeEach(func() { 182 mockProposalResponse.Response = nil 183 mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil) 184 }) 185 186 It("returns an error", func() { 187 err := committer.Commit() 188 Expect(err).To(MatchError("received proposal response with nil response")) 189 }) 190 }) 191 192 Context("when the endorser returns a non-success status", func() { 193 BeforeEach(func() { 194 mockProposalResponse.Response = &pb.Response{ 195 Status: 500, 196 Message: "capuccino", 197 } 198 mockEndorserClient.ProcessProposalReturns(mockProposalResponse, nil) 199 }) 200 201 It("returns an error", func() { 202 err := committer.Commit() 203 Expect(err).To(MatchError("proposal failed with status: 500 - capuccino")) 204 }) 205 }) 206 207 Context("when the signer fails to sign the transaction", func() { 208 BeforeEach(func() { 209 mockSigner.SignReturnsOnCall(1, nil, errors.New("peaberry")) 210 }) 211 212 It("returns an error", func() { 213 err := committer.Commit() 214 Expect(err).To(MatchError("failed to create signed transaction: peaberry")) 215 Expect(mockSigner.SignCallCount()).To(Equal(2)) 216 }) 217 }) 218 219 Context("when the broadcast client fails to send the envelope", func() { 220 BeforeEach(func() { 221 mockBroadcastClient.SendReturns(errors.New("arabica")) 222 }) 223 224 It("returns an error", func() { 225 err := committer.Commit() 226 Expect(err).To(MatchError("failed to send transaction: arabica")) 227 }) 228 }) 229 230 Context("when the wait for event flag is enabled and the transaction is committed", func() { 231 BeforeEach(func() { 232 input.WaitForEvent = true 233 input.WaitForEventTimeout = 3 * time.Second 234 input.TxID = "testtx" 235 input.PeerAddresses = []string{"commitpeer0"} 236 mockDeliverClient.DeliverFilteredStub = func(ctx context.Context, opts ...grpc.CallOption) (pb.Deliver_DeliverFilteredClient, error) { 237 mockDF := &mock.Deliver{} 238 resp := &pb.DeliverResponse{ 239 Type: &pb.DeliverResponse_FilteredBlock{ 240 FilteredBlock: createFilteredBlock(input.ChannelID, "testtx"), 241 }, 242 } 243 mockDF.RecvReturns(resp, nil) 244 return mockDF, nil 245 } 246 }) 247 248 It("waits for the event containing the txid", func() { 249 err := committer.Commit() 250 Expect(err).NotTo(HaveOccurred()) 251 }) 252 }) 253 254 Context("when the wait for event flag is enabled and the client can't connect", func() { 255 BeforeEach(func() { 256 input.WaitForEvent = true 257 input.WaitForEventTimeout = 3 * time.Second 258 input.TxID = "testtx" 259 input.PeerAddresses = []string{"commitpeer0"} 260 mockDeliverClient.DeliverFilteredReturns(nil, errors.New("robusta")) 261 }) 262 263 It("returns an error", func() { 264 err := committer.Commit() 265 Expect(err).To(MatchError("failed to connect to deliver on all peers: error connecting to deliver filtered at commitpeer0: robusta")) 266 }) 267 }) 268 269 Context("when the wait for event flag is enabled and the transaction isn't returned before the timeout", func() { 270 BeforeEach(func() { 271 input.WaitForEvent = true 272 input.WaitForEventTimeout = 10 * time.Millisecond 273 input.TxID = "testtx" 274 input.PeerAddresses = []string{"commitpeer0"} 275 delayChan := make(chan struct{}) 276 mockDeliverClient.DeliverFilteredStub = func(ctx context.Context, opts ...grpc.CallOption) (pb.Deliver_DeliverFilteredClient, error) { 277 mockDF := &mock.Deliver{} 278 mockDF.RecvStub = func() (*pb.DeliverResponse, error) { 279 <-delayChan 280 resp := &pb.DeliverResponse{ 281 Type: &pb.DeliverResponse_FilteredBlock{ 282 FilteredBlock: createFilteredBlock(input.ChannelID, "testtx"), 283 }, 284 } 285 return resp, nil 286 } 287 return mockDF, nil 288 } 289 }) 290 291 It("returns an error", func() { 292 err := committer.Commit() 293 Expect(err).To(MatchError("timed out waiting for txid on all peers")) 294 }) 295 }) 296 }) 297 298 Describe("CommitCmd", func() { 299 var ( 300 commitCmd *cobra.Command 301 ) 302 303 BeforeEach(func() { 304 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 305 Expect(err).To(BeNil()) 306 commitCmd = chaincode.CommitCmd(nil, cryptoProvider) 307 commitCmd.SetArgs([]string{ 308 "--channelID=testchannel", 309 "--name=testcc", 310 "--version=testversion", 311 "--sequence=1", 312 "--peerAddresses=querypeer1", 313 "--tlsRootCertFiles=tls1", 314 "--signature-policy=AND ('Org1MSP.member','Org2MSP.member')", 315 }) 316 }) 317 318 AfterEach(func() { 319 chaincode.ResetFlags() 320 }) 321 322 It("sets up the committer and attempts to commit the chaincode definition", func() { 323 err := commitCmd.Execute() 324 Expect(err).To(MatchError(ContainSubstring("failed to retrieve endorser client"))) 325 }) 326 327 Context("when the policy is invalid", func() { 328 BeforeEach(func() { 329 commitCmd.SetArgs([]string{ 330 "--signature-policy=notapolicy", 331 "--channelID=testchannel", 332 "--name=testcc", 333 "--version=testversion", 334 "--sequence=1", 335 "--peerAddresses=querypeer1", 336 "--tlsRootCertFiles=tls1", 337 }) 338 }) 339 340 It("returns an error", func() { 341 err := commitCmd.Execute() 342 Expect(err).To(MatchError("invalid signature policy: notapolicy")) 343 }) 344 }) 345 346 Context("when the collections config is invalid", func() { 347 BeforeEach(func() { 348 commitCmd.SetArgs([]string{ 349 "--collections-config=idontexist.json", 350 "--channelID=testchannel", 351 "--name=testcc", 352 "--version=testversion", 353 "--sequence=1", 354 "--peerAddresses=querypeer1", 355 "--tlsRootCertFiles=tls1", 356 }) 357 }) 358 359 It("returns an error", func() { 360 err := commitCmd.Execute() 361 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")) 362 }) 363 }) 364 }) 365 })