github.com/zhouxv/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  })