github.com/kaituanwang/hyperledger@v2.0.1+incompatible/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  })