github.com/hyperledger-labs/bdls@v2.1.1+incompatible/core/chaincode/handler_registry_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  	"github.com/hyperledger/fabric/core/chaincode"
    11  	"github.com/hyperledger/fabric/core/chaincode/mock"
    12  	"github.com/hyperledger/fabric/core/common/ccprovider"
    13  	. "github.com/onsi/ginkgo"
    14  	. "github.com/onsi/gomega"
    15  	"github.com/pkg/errors"
    16  )
    17  
    18  var _ = Describe("HandlerRegistry", func() {
    19  	var hr *chaincode.HandlerRegistry
    20  	var handler *chaincode.Handler
    21  
    22  	BeforeEach(func() {
    23  		hr = chaincode.NewHandlerRegistry(true)
    24  		handler = &chaincode.Handler{}
    25  		chaincode.SetHandlerChaincodeID(handler, "chaincode-id")
    26  	})
    27  
    28  	Describe("Launching", func() {
    29  		It("returns a LaunchState to wait on for registration", func() {
    30  			launchState, _ := hr.Launching("chaincode-id")
    31  			Consistently(launchState.Done()).ShouldNot(Receive())
    32  			Consistently(launchState.Done()).ShouldNot(BeClosed())
    33  		})
    34  
    35  		It("indicates whether or not the chaincode needs to start", func() {
    36  			_, started := hr.Launching("chaincode-id")
    37  			Expect(started).To(BeFalse())
    38  		})
    39  
    40  		Context("when a chaincode instance is already launching", func() {
    41  			BeforeEach(func() {
    42  				_, started := hr.Launching("chaincode-id")
    43  				Expect(started).To(BeFalse())
    44  			})
    45  
    46  			It("returns a LaunchState", func() {
    47  				launchState, _ := hr.Launching("chaincode-id")
    48  				Consistently(launchState.Done()).ShouldNot(Receive())
    49  				Consistently(launchState.Done()).ShouldNot(BeClosed())
    50  			})
    51  
    52  			It("indicates already started", func() {
    53  				_, started := hr.Launching("chaincode-id")
    54  				Expect(started).To(BeTrue())
    55  			})
    56  		})
    57  
    58  		Context("when a handler has already been registered", func() {
    59  			BeforeEach(func() {
    60  				err := hr.Register(handler)
    61  				Expect(err).NotTo(HaveOccurred())
    62  			})
    63  
    64  			It("returns a ready LaunchState", func() {
    65  				launchState, _ := hr.Launching("chaincode-id")
    66  				Expect(launchState.Done()).To(BeClosed())
    67  				Expect(launchState.Err()).NotTo(HaveOccurred())
    68  			})
    69  
    70  			It("indicates the chaincode has already been started", func() {
    71  				_, started := hr.Launching("chaincode-id")
    72  				Expect(started).To(BeTrue())
    73  			})
    74  		})
    75  	})
    76  
    77  	Describe("Ready", func() {
    78  		var launchState *chaincode.LaunchState
    79  
    80  		BeforeEach(func() {
    81  			launchState, _ = hr.Launching("chaincode-id")
    82  			Expect(launchState.Done()).NotTo(BeClosed())
    83  		})
    84  
    85  		It("closes the done channel associated with the chaincode id", func() {
    86  			hr.Ready("chaincode-id")
    87  			Expect(launchState.Done()).To(BeClosed())
    88  		})
    89  
    90  		It("does not set an error on launch state", func() {
    91  			hr.Ready("chaincode-id")
    92  			Expect(launchState.Err()).To(BeNil())
    93  		})
    94  
    95  		It("leaves the launching state in the registry", func() {
    96  			hr.Ready("chaincode-id")
    97  			ls, exists := hr.Launching("chaincode-id")
    98  			Expect(exists).To(BeTrue())
    99  			Expect(ls).To(BeIdenticalTo(launchState))
   100  		})
   101  	})
   102  
   103  	Describe("Failed", func() {
   104  		var launchState *chaincode.LaunchState
   105  
   106  		BeforeEach(func() {
   107  			launchState, _ = hr.Launching("chaincode-id")
   108  			Expect(launchState.Done()).NotTo(BeClosed())
   109  		})
   110  
   111  		It("closes the done channel associated with the chaincode id", func() {
   112  			hr.Failed("chaincode-id", errors.New("coconut"))
   113  			Expect(launchState.Done()).To(BeClosed())
   114  		})
   115  
   116  		It("sets a persistent error on launch state", func() {
   117  			hr.Failed("chaincode-id", errors.New("star-fruit"))
   118  			Expect(launchState.Err()).To(MatchError("star-fruit"))
   119  			Expect(launchState.Err()).To(MatchError("star-fruit"))
   120  		})
   121  
   122  		It("leaves the launching state in the registry for explicit cleanup", func() {
   123  			hr.Failed("chaincode-id", errors.New("mango"))
   124  			ls, exists := hr.Launching("chaincode-id")
   125  			Expect(exists).To(BeTrue())
   126  			Expect(ls).To(BeIdenticalTo(launchState))
   127  		})
   128  	})
   129  
   130  	Describe("Handler", func() {
   131  		BeforeEach(func() {
   132  			err := hr.Register(handler)
   133  			Expect(err).NotTo(HaveOccurred())
   134  		})
   135  
   136  		It("returns the registered handler", func() {
   137  			h := hr.Handler("chaincode-id")
   138  			Expect(h).To(BeIdenticalTo(handler))
   139  		})
   140  
   141  		Context("when a handler has not been registered for the chaincode", func() {
   142  			It("returns nil when a handler has not bee registered", func() {
   143  				h := hr.Handler("unregistered-handler-name")
   144  				Expect(h).To(BeNil())
   145  			})
   146  		})
   147  	})
   148  
   149  	Describe("Register", func() {
   150  		Context("when unsolicited registration is disallowed", func() {
   151  			BeforeEach(func() {
   152  				hr = chaincode.NewHandlerRegistry(false)
   153  			})
   154  
   155  			It("disallows direct registrion without launching", func() {
   156  				err := hr.Register(handler)
   157  				Expect(err).To(MatchError(`peer will not accept external chaincode connection chaincode-id (except in dev mode)`))
   158  
   159  				h := hr.Handler("chaincode-id")
   160  				Expect(h).To(BeNil())
   161  			})
   162  
   163  			It("allows registration of launching chaincode", func() {
   164  				_, started := hr.Launching("chaincode-id")
   165  				Expect(started).To(BeFalse())
   166  
   167  				err := hr.Register(handler)
   168  				Expect(err).NotTo(HaveOccurred())
   169  
   170  				h := hr.Handler("chaincode-id")
   171  				Expect(h).To(Equal(handler))
   172  			})
   173  		})
   174  
   175  		Context("when unsolicited registrations are allowed", func() {
   176  			BeforeEach(func() {
   177  				hr = chaincode.NewHandlerRegistry(true)
   178  			})
   179  
   180  			It("allows direct registration without launching", func() {
   181  				err := hr.Register(handler)
   182  				Expect(err).NotTo(HaveOccurred())
   183  
   184  				h := hr.Handler("chaincode-id")
   185  				Expect(h).To(BeIdenticalTo(handler))
   186  			})
   187  		})
   188  
   189  		Context("when a handler has already been registered", func() {
   190  			BeforeEach(func() {
   191  				hr = chaincode.NewHandlerRegistry(true)
   192  				err := hr.Register(handler)
   193  				Expect(err).NotTo(HaveOccurred())
   194  			})
   195  
   196  			It("returns an error", func() {
   197  				err := hr.Register(handler)
   198  				Expect(err).To(MatchError("duplicate chaincodeID: chaincode-id"))
   199  			})
   200  		})
   201  	})
   202  
   203  	Describe("Deregister", func() {
   204  		var fakeResultsIterator *mock.QueryResultsIterator
   205  
   206  		BeforeEach(func() {
   207  			fakeResultsIterator = &mock.QueryResultsIterator{}
   208  			transactionContexts := chaincode.NewTransactionContexts()
   209  
   210  			txContext, err := transactionContexts.Create(&ccprovider.TransactionParams{
   211  				ChannelID: "chain-id",
   212  				TxID:      "transaction-id",
   213  			})
   214  			Expect(err).NotTo(HaveOccurred())
   215  
   216  			handler.TXContexts = transactionContexts
   217  			txContext.InitializeQueryContext("query-id", fakeResultsIterator)
   218  
   219  			_, started := hr.Launching("chaincode-id")
   220  			Expect(started).To(BeFalse())
   221  
   222  			err = hr.Register(handler)
   223  			Expect(err).NotTo(HaveOccurred())
   224  		})
   225  
   226  		It("removes references to the handler", func() {
   227  			err := hr.Deregister("chaincode-id")
   228  			Expect(err).NotTo(HaveOccurred())
   229  
   230  			handler := hr.Handler("chaincode-id")
   231  			Expect(handler).To(BeNil())
   232  			_, exists := hr.Launching("chaincode-id")
   233  			Expect(exists).To(BeFalse())
   234  		})
   235  
   236  		It("closes transaction contexts", func() {
   237  			err := hr.Deregister("chaincode-id")
   238  			Expect(err).NotTo(HaveOccurred())
   239  
   240  			Expect(fakeResultsIterator.CloseCallCount()).To(Equal(1))
   241  		})
   242  	})
   243  })
   244  
   245  var _ = Describe("LaunchState", func() {
   246  	var launchState *chaincode.LaunchState
   247  
   248  	BeforeEach(func() {
   249  		launchState = chaincode.NewLaunchState()
   250  	})
   251  
   252  	It("coordinates notification and errors", func() {
   253  		Expect(launchState.Done()).NotTo(BeNil())
   254  		Consistently(launchState.Done()).ShouldNot(BeClosed())
   255  
   256  		launchState.Notify(errors.New("jelly"))
   257  		Eventually(launchState.Done()).Should(BeClosed())
   258  		Expect(launchState.Err()).To(MatchError("jelly"))
   259  	})
   260  
   261  	It("can notify with a nil error", func() {
   262  		Expect(launchState.Done()).NotTo(BeNil())
   263  		Consistently(launchState.Done()).ShouldNot(BeClosed())
   264  
   265  		launchState.Notify(nil)
   266  		Eventually(launchState.Done()).Should(BeClosed())
   267  		Expect(launchState.Err()).To(BeNil())
   268  	})
   269  
   270  	It("can be notified mulitple times but honors the first", func() {
   271  		Expect(launchState.Done()).NotTo(BeNil())
   272  		Consistently(launchState.Done()).ShouldNot(BeClosed())
   273  
   274  		launchState.Notify(errors.New("mango"))
   275  		launchState.Notify(errors.New("tango"))
   276  		launchState.Notify(errors.New("django"))
   277  		launchState.Notify(nil)
   278  		Eventually(launchState.Done()).Should(BeClosed())
   279  		Expect(launchState.Err()).To(MatchError("mango"))
   280  	})
   281  })
   282  
   283  var _ = Describe("TxSimulatorGetter", func() {
   284  	var (
   285  		hr              *chaincode.HandlerRegistry
   286  		handler         *chaincode.Handler
   287  		txQEGetter      *chaincode.TxQueryExecutorGetter
   288  		fakeTxSimulator *mock.TxSimulator
   289  	)
   290  
   291  	BeforeEach(func() {
   292  		hr = chaincode.NewHandlerRegistry(true)
   293  		handler = &chaincode.Handler{
   294  			TXContexts: chaincode.NewTransactionContexts(),
   295  		}
   296  		fakeTxSimulator = &mock.TxSimulator{}
   297  		txQEGetter = &chaincode.TxQueryExecutorGetter{
   298  			HandlerRegistry: hr,
   299  			CCID:            "chaincode-id",
   300  		}
   301  	})
   302  
   303  	When("No Handler is created for chaincode-id", func() {
   304  		It("returns a nil TxSimulator", func() {
   305  			sim := txQEGetter.TxQueryExecutor("channel-ID", "tx-ID")
   306  			Expect(sim).To(BeNil())
   307  		})
   308  	})
   309  
   310  	When("No TxContext is created", func() {
   311  		BeforeEach(func() {
   312  			chaincode.SetHandlerChaincodeID(handler, "chaincode-id")
   313  			hr.Register(handler)
   314  		})
   315  
   316  		It("returns a nil TxSimulator", func() {
   317  			sim := txQEGetter.TxQueryExecutor("channel-ID", "tx-ID")
   318  			Expect(sim).To(BeNil())
   319  		})
   320  	})
   321  
   322  	When("Handler is created for chaincode-id and TxContext is created for channel-ID/tx-ID", func() {
   323  		BeforeEach(func() {
   324  			chaincode.SetHandlerChaincodeID(handler, "chaincode-id")
   325  			hr.Register(handler)
   326  			handler.TXContexts.Create(&ccprovider.TransactionParams{
   327  				ChannelID:   "channel-ID",
   328  				TxID:        "tx-ID",
   329  				TXSimulator: fakeTxSimulator,
   330  			})
   331  		})
   332  		It("returns associated TxSimulator", func() {
   333  			sim := txQEGetter.TxQueryExecutor("channel-ID", "tx-ID")
   334  			Expect(sim).To(Equal(fakeTxSimulator))
   335  		})
   336  	})
   337  })