github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/core/chaincode/chaincode_ginkgo_support_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 "fmt" 11 "unicode/utf8" 12 13 pb "github.com/hyperledger/fabric-protos-go/peer" 14 "github.com/hyperledger/fabric/core/chaincode" 15 "github.com/hyperledger/fabric/core/chaincode/lifecycle" 16 "github.com/hyperledger/fabric/core/chaincode/mock" 17 "github.com/hyperledger/fabric/core/common/ccprovider" 18 19 . "github.com/onsi/ginkgo" 20 . "github.com/onsi/gomega" 21 ) 22 23 var _ = Describe("CheckInvocation", func() { 24 var ( 25 chaincodeSupport *chaincode.ChaincodeSupport 26 invokeInfo *lifecycle.ChaincodeEndorsementInfo 27 28 fakeLifecycle *mock.Lifecycle 29 fakeSimulator *mock.TxSimulator 30 31 txParams *ccprovider.TransactionParams 32 input *pb.ChaincodeInput 33 ) 34 35 BeforeEach(func() { 36 fakeLifecycle = &mock.Lifecycle{} 37 fakeSimulator = &mock.TxSimulator{} 38 fakeSimulator.GetStateReturns([]byte("old-cc-version"), nil) 39 40 invokeInfo = &lifecycle.ChaincodeEndorsementInfo{ 41 Version: "definition-version", 42 ChaincodeID: "definition-ccid", 43 } 44 45 fakeLifecycle.ChaincodeEndorsementInfoReturns(invokeInfo, nil) 46 47 txParams = &ccprovider.TransactionParams{ 48 ChannelID: "channel-id", 49 TXSimulator: fakeSimulator, 50 } 51 52 input = &pb.ChaincodeInput{} 53 54 chaincodeSupport = &chaincode.ChaincodeSupport{ 55 Lifecycle: fakeLifecycle, 56 } 57 }) 58 59 It("fetches the info and returns the ccid and type", func() { 60 ccid, cctype, err := chaincodeSupport.CheckInvocation(txParams, "test-chaincode-name", input) 61 Expect(err).NotTo(HaveOccurred()) 62 Expect(ccid).To(Equal("definition-ccid")) 63 Expect(cctype).To(Equal(pb.ChaincodeMessage_TRANSACTION)) 64 }) 65 66 Context("when the invocation is an init", func() { 67 BeforeEach(func() { 68 input.IsInit = true 69 }) 70 71 It("returns an error for chaincodes which do not require init", func() { 72 _, _, err := chaincodeSupport.CheckInvocation(txParams, "test-chaincode-name", input) 73 Expect(err).To(MatchError("chaincode 'test-chaincode-name' does not require initialization but called as init")) 74 }) 75 76 Context("when the chaincode requires init be enforced", func() { 77 BeforeEach(func() { 78 invokeInfo.EnforceInit = true 79 }) 80 81 It("enforces init exactly once semantics", func() { 82 ccid, cctype, err := chaincodeSupport.CheckInvocation(txParams, "test-chaincode-name", input) 83 Expect(err).NotTo(HaveOccurred()) 84 Expect(ccid).To(Equal("definition-ccid")) 85 Expect(cctype).To(Equal(pb.ChaincodeMessage_INIT)) 86 87 Expect(fakeSimulator.GetStateCallCount()).To(Equal(1)) 88 namespace, key := fakeSimulator.GetStateArgsForCall(0) 89 Expect(namespace).To(Equal("test-chaincode-name")) 90 Expect(key).To(Equal("\x00" + string(utf8.MaxRune) + "initialized")) 91 92 Expect(fakeSimulator.SetStateCallCount()).To(Equal(1)) 93 namespace, key, value := fakeSimulator.SetStateArgsForCall(0) 94 Expect(namespace).To(Equal("test-chaincode-name")) 95 Expect(key).To(Equal("\x00" + string(utf8.MaxRune) + "initialized")) 96 Expect(value).To(Equal([]byte("definition-version"))) 97 }) 98 99 Context("when the invocation is not an init", func() { 100 BeforeEach(func() { 101 input.IsInit = false 102 }) 103 104 It("returns an error", func() { 105 _, _, err := chaincodeSupport.CheckInvocation(txParams, "test-chaincode-name", input) 106 Expect(err).To(MatchError("chaincode 'test-chaincode-name' has not been initialized for this version, must call as init first")) 107 }) 108 }) 109 110 Context("when the chaincode is already initialized", func() { 111 BeforeEach(func() { 112 fakeSimulator.GetStateReturns([]byte("definition-version"), nil) 113 }) 114 115 It("returns an error", func() { 116 _, _, err := chaincodeSupport.CheckInvocation(txParams, "test-chaincode-name", input) 117 Expect(err).To(MatchError("chaincode 'test-chaincode-name' is already initialized but called as init")) 118 }) 119 }) 120 121 Context("when the txsimulator cannot get state", func() { 122 BeforeEach(func() { 123 fakeSimulator.GetStateReturns(nil, fmt.Errorf("get-state-error")) 124 }) 125 126 It("wraps and returns the error", func() { 127 _, _, err := chaincodeSupport.CheckInvocation(txParams, "test-chaincode-name", input) 128 Expect(err).To(MatchError("could not get 'initialized' key: get-state-error")) 129 }) 130 }) 131 132 Context("when the txsimulator cannot set state", func() { 133 BeforeEach(func() { 134 fakeSimulator.SetStateReturns(fmt.Errorf("set-state-error")) 135 }) 136 137 It("wraps and returns the error", func() { 138 _, _, err := chaincodeSupport.CheckInvocation(txParams, "test-chaincode-name", input) 139 Expect(err).To(MatchError("could not set 'initialized' key: set-state-error")) 140 }) 141 }) 142 }) 143 }) 144 145 Context("when lifecycle returns an error", func() { 146 BeforeEach(func() { 147 fakeLifecycle.ChaincodeEndorsementInfoReturns(nil, fmt.Errorf("fake-lifecycle-error")) 148 }) 149 150 It("wraps and returns the error", func() { 151 _, _, err := chaincodeSupport.CheckInvocation(txParams, "test-chaincode-name", input) 152 Expect(err).To(MatchError("[channel channel-id] failed to get chaincode container info for test-chaincode-name: fake-lifecycle-error")) 153 }) 154 }) 155 })