github.com/anjalikarhana/fabric@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 })