github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/chaincode/lifecycle/endorsement_info_test.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package lifecycle_test 8 9 import ( 10 "fmt" 11 12 "github.com/hechain20/hechain/core/chaincode/lifecycle" 13 "github.com/hechain20/hechain/core/chaincode/lifecycle/mock" 14 "github.com/hechain20/hechain/core/scc" 15 lb "github.com/hyperledger/fabric-protos-go/peer/lifecycle" 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 Describe("CachedChaincodeInfo", func() { 102 It("returns the info from the cache", func() { 103 info, ok, err := cei.CachedChaincodeInfo("channel-id", "name", fakeQueryExecutor) 104 Expect(err).NotTo(HaveOccurred()) 105 Expect(ok).To(BeTrue()) 106 Expect(info).To(Equal(&lifecycle.LocalChaincodeInfo{ 107 Definition: &lifecycle.ChaincodeDefinition{ 108 Sequence: 7, 109 EndorsementInfo: &lb.ChaincodeEndorsementInfo{ 110 Version: "version", 111 EndorsementPlugin: "endorsement-plugin", 112 }, 113 ValidationInfo: &lb.ChaincodeValidationInfo{ 114 ValidationPlugin: "validation-plugin", 115 ValidationParameter: []byte("validation-parameter"), 116 }, 117 }, 118 InstallInfo: &lifecycle.ChaincodeInstallInfo{ 119 Type: "fake-type", 120 Path: "fake-path", 121 PackageID: "hash", 122 }, 123 Approved: true, 124 })) 125 Expect(fakeCache.ChaincodeInfoCallCount()).To(Equal(1)) 126 channelID, chaincodeName := fakeCache.ChaincodeInfoArgsForCall(0) 127 Expect(channelID).To(Equal("channel-id")) 128 Expect(chaincodeName).To(Equal("name")) 129 }) 130 131 Context("when the cache returns an error", func() { 132 BeforeEach(func() { 133 fakeCache.ChaincodeInfoReturns(nil, fmt.Errorf("cache-error")) 134 }) 135 136 It("wraps and returns the error", func() { 137 _, _, err := cei.CachedChaincodeInfo("channel-id", "name", fakeQueryExecutor) 138 Expect(err).To(MatchError("could not get approved chaincode info from cache: cache-error")) 139 }) 140 }) 141 142 Context("when the cache has not been approved", func() { 143 BeforeEach(func() { 144 testInfo.Approved = false 145 }) 146 147 It("returns an error", func() { 148 _, _, err := cei.CachedChaincodeInfo("channel-id", "name", fakeQueryExecutor) 149 Expect(err).To(MatchError("chaincode definition for 'name' at sequence 7 on channel 'channel-id' has not yet been approved by this org")) 150 }) 151 }) 152 153 Context("when the chaincode has not been installed", func() { 154 BeforeEach(func() { 155 testInfo.InstallInfo = nil 156 }) 157 158 It("returns an error", func() { 159 _, _, err := cei.CachedChaincodeInfo("channel-id", "name", fakeQueryExecutor) 160 Expect(err).To(MatchError("chaincode definition for 'name' exists, but chaincode is not installed")) 161 }) 162 }) 163 164 Context("when the cache does not match the current sequence", func() { 165 BeforeEach(func() { 166 testInfo.Definition.Sequence = 5 167 }) 168 169 It("returns an error", func() { 170 _, _, err := cei.CachedChaincodeInfo("channel-id", "name", fakeQueryExecutor) 171 Expect(err).To(MatchError("chaincode cache at sequence 5 but current sequence is 7, chaincode definition for 'name' changed during invoke")) 172 }) 173 }) 174 175 Context("when the sequence cannot be fetched from the state", func() { 176 BeforeEach(func() { 177 fakeQueryExecutor.GetStateReturns(nil, fmt.Errorf("state-error")) 178 }) 179 180 It("wraps and returns an error", func() { 181 _, _, err := cei.CachedChaincodeInfo("channel-id", "name", fakeQueryExecutor) 182 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")) 183 }) 184 }) 185 186 Context("when the query executor is nil", func() { 187 It("uses the dummy query executor and returns an error", func() { 188 _, _, err := cei.CachedChaincodeInfo("", "name", nil) 189 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")) 190 }) 191 }) 192 193 Context("when running chaincode in devmode", func() { 194 BeforeEach(func() { 195 testInfo.InstallInfo = nil 196 cei.UserRunsCC = true 197 }) 198 199 It("set chaincode installInfo to {chaincodeName}:{chaincodeVersion}", func() { 200 info, ok, err := cei.CachedChaincodeInfo("channel-id", "name", fakeQueryExecutor) 201 Expect(err).NotTo(HaveOccurred()) 202 Expect(ok).To(BeTrue()) 203 Expect(info).To(Equal(&lifecycle.LocalChaincodeInfo{ 204 Definition: &lifecycle.ChaincodeDefinition{ 205 Sequence: 7, 206 EndorsementInfo: &lb.ChaincodeEndorsementInfo{ 207 Version: "version", 208 EndorsementPlugin: "endorsement-plugin", 209 }, 210 ValidationInfo: &lb.ChaincodeValidationInfo{ 211 ValidationPlugin: "validation-plugin", 212 ValidationParameter: []byte("validation-parameter"), 213 }, 214 }, 215 InstallInfo: &lifecycle.ChaincodeInstallInfo{ 216 PackageID: "name:version", 217 }, 218 Approved: true, 219 })) 220 Expect(fakeCache.ChaincodeInfoCallCount()).To(Equal(1)) 221 channelID, chaincodeName := fakeCache.ChaincodeInfoArgsForCall(0) 222 Expect(channelID).To(Equal("channel-id")) 223 Expect(chaincodeName).To(Equal("name")) 224 }) 225 }) 226 }) 227 228 Describe("ChaincodeEndorsementInfo", func() { 229 It("adapts the underlying lifecycle response", func() { 230 def, err := cei.ChaincodeEndorsementInfo("channel-id", "name", fakeQueryExecutor) 231 Expect(err).NotTo(HaveOccurred()) 232 Expect(def).To(Equal(&lifecycle.ChaincodeEndorsementInfo{ 233 Version: "version", 234 EndorsementPlugin: "endorsement-plugin", 235 ChaincodeID: "hash", 236 })) 237 }) 238 239 Context("when the chaincode is a builtin system chaincode", func() { 240 BeforeEach(func() { 241 builtinSCCs["test-syscc-name"] = struct{}{} 242 }) 243 244 It("returns a static definition", func() { 245 res, err := cei.ChaincodeEndorsementInfo("channel-id", "test-syscc-name", fakeQueryExecutor) 246 Expect(err).NotTo(HaveOccurred()) 247 Expect(res).To(Equal(&lifecycle.ChaincodeEndorsementInfo{ 248 Version: "syscc", 249 ChaincodeID: "test-syscc-name.syscc", 250 EndorsementPlugin: "escc", 251 })) 252 }) 253 }) 254 255 Context("when the cache returns an error", func() { 256 BeforeEach(func() { 257 fakeCache.ChaincodeInfoReturns(nil, fmt.Errorf("cache-error")) 258 }) 259 260 It("returns the wrapped error", func() { 261 _, err := cei.ChaincodeEndorsementInfo("channel-id", "name", fakeQueryExecutor) 262 Expect(err).To(MatchError("could not get approved chaincode info from cache: cache-error")) 263 }) 264 }) 265 266 Context("when the chaincode is not defined in the new lifecycle", func() { 267 BeforeEach(func() { 268 delete(fakePublicState, "namespaces/fields/name/Sequence") 269 fakeLegacyImpl.ChaincodeEndorsementInfoReturns(&lifecycle.ChaincodeEndorsementInfo{ 270 Version: "legacy-version", 271 EndorsementPlugin: "legacy-plugin", 272 ChaincodeID: "legacy-id", 273 }, fmt.Errorf("fake-error")) 274 }) 275 276 It("passes through the legacy implementation", func() { 277 res, err := cei.ChaincodeEndorsementInfo("channel-id", "cc-name", fakeQueryExecutor) 278 Expect(err).To(MatchError("fake-error")) 279 Expect(res).To(Equal(&lifecycle.ChaincodeEndorsementInfo{ 280 Version: "legacy-version", 281 EndorsementPlugin: "legacy-plugin", 282 ChaincodeID: "legacy-id", 283 })) 284 Expect(fakeLegacyImpl.ChaincodeEndorsementInfoCallCount()).To(Equal(1)) 285 channelID, name, qe := fakeLegacyImpl.ChaincodeEndorsementInfoArgsForCall(0) 286 Expect(channelID).To(Equal("channel-id")) 287 Expect(name).To(Equal("cc-name")) 288 Expect(qe).To(Equal(fakeQueryExecutor)) 289 }) 290 }) 291 }) 292 293 Context("when LifecycleV20 capability is not enabled", func() { 294 var ccEndorsementInfo *lifecycle.ChaincodeEndorsementInfo 295 296 BeforeEach(func() { 297 ccEndorsementInfo = &lifecycle.ChaincodeEndorsementInfo{ 298 Version: "legacy-version", 299 EndorsementPlugin: "legacy-plugin", 300 ChaincodeID: "legacy-id", 301 } 302 fakeCapabilities.LifecycleV20Returns(false) 303 fakeLegacyImpl.ChaincodeEndorsementInfoReturns(ccEndorsementInfo, nil) 304 }) 305 306 It("returns the legacy chaincode info", func() { 307 res, err := cei.ChaincodeEndorsementInfo("channel-id", "cc-name", fakeQueryExecutor) 308 Expect(err).NotTo(HaveOccurred()) 309 Expect(res).To(Equal(ccEndorsementInfo)) 310 Expect(fakeLegacyImpl.ChaincodeEndorsementInfoCallCount()).To(Equal(1)) 311 channelID, name, qe := fakeLegacyImpl.ChaincodeEndorsementInfoArgsForCall(0) 312 Expect(channelID).To(Equal("channel-id")) 313 Expect(name).To(Equal("cc-name")) 314 Expect(qe).To(Equal(fakeQueryExecutor)) 315 }) 316 }) 317 318 Context("when channel config is not found", func() { 319 BeforeEach(func() { 320 fakeChannelConfigSource.GetStableChannelConfigReturns(nil) 321 }) 322 323 It("returns not get channel config error", func() { 324 _, err := cei.ChaincodeEndorsementInfo("channel-id", "cc-name", fakeQueryExecutor) 325 Expect(err).To(MatchError("could not get channel config for channel 'channel-id'")) 326 }) 327 }) 328 329 Context("when application config is not found", func() { 330 BeforeEach(func() { 331 fakeChannelConfig.ApplicationConfigReturns(nil, false) 332 }) 333 334 It("returns not get application config error", func() { 335 _, err := cei.ChaincodeEndorsementInfo("channel-id", "cc-name", fakeQueryExecutor) 336 Expect(err).To(MatchError("could not get application config for channel 'channel-id'")) 337 }) 338 }) 339 })