github.com/defanghe/fabric@v2.1.1+incompatible/core/chaincode/lifecycle/endorsment_info_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package lifecycle_test 8 9 import ( 10 "fmt" 11 12 lb "github.com/hyperledger/fabric-protos-go/peer/lifecycle" 13 "github.com/hyperledger/fabric/core/chaincode/lifecycle" 14 "github.com/hyperledger/fabric/core/chaincode/lifecycle/mock" 15 "github.com/hyperledger/fabric/core/scc" 16 17 . "github.com/onsi/ginkgo" 18 . "github.com/onsi/gomega" 19 ) 20 21 var _ = Describe("ChaincodeEndorsementInfoSource", func() { 22 var ( 23 cei *lifecycle.ChaincodeEndorsementInfoSource 24 resources *lifecycle.Resources 25 fakeLegacyImpl *mock.LegacyLifecycle 26 fakePublicState MapLedgerShim 27 fakeQueryExecutor *mock.SimpleQueryExecutor 28 fakeCache *mock.ChaincodeInfoCache 29 fakeChannelConfigSource *mock.ChannelConfigSource 30 fakeChannelConfig *mock.ChannelConfig 31 fakeAppConfig *mock.ApplicationConfig 32 fakeCapabilities *mock.ApplicationCapabilities 33 testInfo *lifecycle.LocalChaincodeInfo 34 builtinSCCs scc.BuiltinSCCs 35 ) 36 37 BeforeEach(func() { 38 fakeLegacyImpl = &mock.LegacyLifecycle{} 39 fakeChannelConfigSource = &mock.ChannelConfigSource{} 40 fakeChannelConfig = &mock.ChannelConfig{} 41 fakeAppConfig = &mock.ApplicationConfig{} 42 fakeCapabilities = &mock.ApplicationCapabilities{} 43 fakeChannelConfigSource.GetStableChannelConfigReturns(fakeChannelConfig) 44 fakeChannelConfig.ApplicationConfigReturns(fakeAppConfig, true) 45 fakeAppConfig.CapabilitiesReturns(fakeCapabilities) 46 fakeCapabilities.LifecycleV20Returns(true) 47 48 resources = &lifecycle.Resources{ 49 Serializer: &lifecycle.Serializer{}, 50 ChannelConfigSource: fakeChannelConfigSource, 51 } 52 53 fakePublicState = MapLedgerShim(map[string][]byte{}) 54 fakeQueryExecutor = &mock.SimpleQueryExecutor{} 55 fakeQueryExecutor.GetStateStub = func(namespace, key string) ([]byte, error) { 56 return fakePublicState.GetState(key) 57 } 58 59 builtinSCCs = map[string]struct{}{} 60 61 err := resources.Serializer.Serialize(lifecycle.NamespacesName, 62 "name", 63 &lifecycle.ChaincodeDefinition{ 64 Sequence: 7, 65 }, 66 fakePublicState, 67 ) 68 Expect(err).NotTo(HaveOccurred()) 69 70 testInfo = &lifecycle.LocalChaincodeInfo{ 71 Definition: &lifecycle.ChaincodeDefinition{ 72 Sequence: 7, 73 EndorsementInfo: &lb.ChaincodeEndorsementInfo{ 74 Version: "version", 75 EndorsementPlugin: "endorsement-plugin", 76 }, 77 ValidationInfo: &lb.ChaincodeValidationInfo{ 78 ValidationPlugin: "validation-plugin", 79 ValidationParameter: []byte("validation-parameter"), 80 }, 81 }, 82 InstallInfo: &lifecycle.ChaincodeInstallInfo{ 83 Path: "fake-path", 84 Type: "fake-type", 85 PackageID: "hash", 86 }, 87 Approved: true, 88 } 89 90 fakeCache = &mock.ChaincodeInfoCache{} 91 fakeCache.ChaincodeInfoReturns(testInfo, nil) 92 93 cei = &lifecycle.ChaincodeEndorsementInfoSource{ 94 LegacyImpl: fakeLegacyImpl, 95 Resources: resources, 96 Cache: fakeCache, 97 BuiltinSCCs: builtinSCCs, 98 } 99 100 }) 101 102 Describe("CachedChaincodeInfo", func() { 103 It("returns the info from the cache", func() { 104 info, ok, err := cei.CachedChaincodeInfo("channel-id", "name", fakeQueryExecutor) 105 Expect(err).NotTo(HaveOccurred()) 106 Expect(ok).To(BeTrue()) 107 Expect(info).To(Equal(&lifecycle.LocalChaincodeInfo{ 108 Definition: &lifecycle.ChaincodeDefinition{ 109 Sequence: 7, 110 EndorsementInfo: &lb.ChaincodeEndorsementInfo{ 111 Version: "version", 112 EndorsementPlugin: "endorsement-plugin", 113 }, 114 ValidationInfo: &lb.ChaincodeValidationInfo{ 115 ValidationPlugin: "validation-plugin", 116 ValidationParameter: []byte("validation-parameter"), 117 }, 118 }, 119 InstallInfo: &lifecycle.ChaincodeInstallInfo{ 120 Type: "fake-type", 121 Path: "fake-path", 122 PackageID: "hash", 123 }, 124 Approved: true, 125 })) 126 Expect(fakeCache.ChaincodeInfoCallCount()).To(Equal(1)) 127 channelID, chaincodeName := fakeCache.ChaincodeInfoArgsForCall(0) 128 Expect(channelID).To(Equal("channel-id")) 129 Expect(chaincodeName).To(Equal("name")) 130 }) 131 132 Context("when the cache returns an error", func() { 133 BeforeEach(func() { 134 fakeCache.ChaincodeInfoReturns(nil, fmt.Errorf("cache-error")) 135 }) 136 137 It("wraps and returns the error", func() { 138 _, _, err := cei.CachedChaincodeInfo("channel-id", "name", fakeQueryExecutor) 139 Expect(err).To(MatchError("could not get approved chaincode info from cache: cache-error")) 140 }) 141 }) 142 143 Context("when the cache has not been approved", func() { 144 BeforeEach(func() { 145 testInfo.Approved = false 146 }) 147 148 It("returns an error", func() { 149 _, _, err := cei.CachedChaincodeInfo("channel-id", "name", fakeQueryExecutor) 150 Expect(err).To(MatchError("chaincode definition for 'name' at sequence 7 on channel 'channel-id' has not yet been approved by this org")) 151 }) 152 }) 153 154 Context("when the chaincode has not been installed", func() { 155 BeforeEach(func() { 156 testInfo.InstallInfo = nil 157 }) 158 159 It("returns an error", func() { 160 _, _, err := cei.CachedChaincodeInfo("channel-id", "name", fakeQueryExecutor) 161 Expect(err).To(MatchError("chaincode definition for 'name' exists, but chaincode is not installed")) 162 }) 163 }) 164 165 Context("when the cache does not match the current sequence", func() { 166 BeforeEach(func() { 167 testInfo.Definition.Sequence = 5 168 }) 169 170 It("returns an error", func() { 171 _, _, err := cei.CachedChaincodeInfo("channel-id", "name", fakeQueryExecutor) 172 Expect(err).To(MatchError("chaincode cache at sequence 5 but current sequence is 7, chaincode definition for 'name' changed during invoke")) 173 }) 174 }) 175 176 Context("when the sequence cannot be fetched from the state", func() { 177 BeforeEach(func() { 178 fakeQueryExecutor.GetStateReturns(nil, fmt.Errorf("state-error")) 179 }) 180 181 It("wraps and returns an error", func() { 182 _, _, err := cei.CachedChaincodeInfo("channel-id", "name", fakeQueryExecutor) 183 Expect(err).To(MatchError("could not get current sequence for chaincode 'name' on channel 'channel-id': could not get state for key namespaces/fields/name/Sequence: state-error")) 184 }) 185 }) 186 187 Context("when the query executor is nil", func() { 188 It("uses the dummy query executor and returns an error", func() { 189 _, _, err := cei.CachedChaincodeInfo("", "name", nil) 190 Expect(err).To(MatchError("could not get current sequence for chaincode 'name' on channel '': could not get state for key namespaces/fields/name/Sequence: invalid channel-less operation")) 191 }) 192 }) 193 }) 194 195 Describe("ChaincodeEndorsementInfo", func() { 196 It("adapts the underlying lifecycle response", func() { 197 def, err := cei.ChaincodeEndorsementInfo("channel-id", "name", fakeQueryExecutor) 198 Expect(err).NotTo(HaveOccurred()) 199 Expect(def).To(Equal(&lifecycle.ChaincodeEndorsementInfo{ 200 Version: "version", 201 EndorsementPlugin: "endorsement-plugin", 202 ChaincodeID: "hash", 203 })) 204 }) 205 206 Context("when the chaincode is a builtin system chaincode", func() { 207 BeforeEach(func() { 208 builtinSCCs["test-syscc-name"] = struct{}{} 209 }) 210 211 It("returns a static definition", func() { 212 res, err := cei.ChaincodeEndorsementInfo("channel-id", "test-syscc-name", fakeQueryExecutor) 213 Expect(err).NotTo(HaveOccurred()) 214 Expect(res).To(Equal(&lifecycle.ChaincodeEndorsementInfo{ 215 Version: "syscc", 216 ChaincodeID: "test-syscc-name.syscc", 217 EndorsementPlugin: "escc", 218 })) 219 }) 220 }) 221 222 Context("when the cache returns an error", func() { 223 BeforeEach(func() { 224 fakeCache.ChaincodeInfoReturns(nil, fmt.Errorf("cache-error")) 225 }) 226 227 It("returns the wrapped error", func() { 228 _, err := cei.ChaincodeEndorsementInfo("channel-id", "name", fakeQueryExecutor) 229 Expect(err).To(MatchError("could not get approved chaincode info from cache: cache-error")) 230 }) 231 }) 232 233 Context("when the chaincode is not defined in the new lifecycle", func() { 234 BeforeEach(func() { 235 delete(fakePublicState, "namespaces/fields/name/Sequence") 236 fakeLegacyImpl.ChaincodeEndorsementInfoReturns(&lifecycle.ChaincodeEndorsementInfo{ 237 Version: "legacy-version", 238 EndorsementPlugin: "legacy-plugin", 239 ChaincodeID: "legacy-id", 240 }, fmt.Errorf("fake-error")) 241 }) 242 243 It("passes through the legacy implementation", func() { 244 res, err := cei.ChaincodeEndorsementInfo("channel-id", "cc-name", fakeQueryExecutor) 245 Expect(err).To(MatchError("fake-error")) 246 Expect(res).To(Equal(&lifecycle.ChaincodeEndorsementInfo{ 247 Version: "legacy-version", 248 EndorsementPlugin: "legacy-plugin", 249 ChaincodeID: "legacy-id", 250 })) 251 Expect(fakeLegacyImpl.ChaincodeEndorsementInfoCallCount()).To(Equal(1)) 252 channelID, name, qe := fakeLegacyImpl.ChaincodeEndorsementInfoArgsForCall(0) 253 Expect(channelID).To(Equal("channel-id")) 254 Expect(name).To(Equal("cc-name")) 255 Expect(qe).To(Equal(fakeQueryExecutor)) 256 }) 257 }) 258 }) 259 260 Context("when LifecycleV20 capability is not enabled", func() { 261 var ccEndorsementInfo *lifecycle.ChaincodeEndorsementInfo 262 263 BeforeEach(func() { 264 ccEndorsementInfo = &lifecycle.ChaincodeEndorsementInfo{ 265 Version: "legacy-version", 266 EndorsementPlugin: "legacy-plugin", 267 ChaincodeID: "legacy-id", 268 } 269 fakeCapabilities.LifecycleV20Returns(false) 270 fakeLegacyImpl.ChaincodeEndorsementInfoReturns(ccEndorsementInfo, nil) 271 }) 272 273 It("returns the legacy chaincode info", func() { 274 res, err := cei.ChaincodeEndorsementInfo("channel-id", "cc-name", fakeQueryExecutor) 275 Expect(err).NotTo(HaveOccurred()) 276 Expect(res).To(Equal(ccEndorsementInfo)) 277 Expect(fakeLegacyImpl.ChaincodeEndorsementInfoCallCount()).To(Equal(1)) 278 channelID, name, qe := fakeLegacyImpl.ChaincodeEndorsementInfoArgsForCall(0) 279 Expect(channelID).To(Equal("channel-id")) 280 Expect(name).To(Equal("cc-name")) 281 Expect(qe).To(Equal(fakeQueryExecutor)) 282 }) 283 }) 284 285 Context("when channel config is not found", func() { 286 BeforeEach(func() { 287 fakeChannelConfigSource.GetStableChannelConfigReturns(nil) 288 }) 289 290 It("returns not get channel config error", func() { 291 _, err := cei.ChaincodeEndorsementInfo("channel-id", "cc-name", fakeQueryExecutor) 292 Expect(err).To(MatchError("could not get channel config for channel 'channel-id'")) 293 }) 294 }) 295 296 Context("when application config is not found", func() { 297 BeforeEach(func() { 298 fakeChannelConfig.ApplicationConfigReturns(nil, false) 299 }) 300 301 It("returns not get application config error", func() { 302 _, err := cei.ChaincodeEndorsementInfo("channel-id", "cc-name", fakeQueryExecutor) 303 Expect(err).To(MatchError("could not get application config for channel 'channel-id'")) 304 }) 305 }) 306 })