github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/chaincode/persistence/chaincode_package_test.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package persistence_test
     8  
     9  import (
    10  	"io/ioutil"
    11  
    12  	"github.com/hechain20/hechain/core/chaincode/persistence"
    13  	"github.com/hechain20/hechain/core/chaincode/persistence/mock"
    14  	pb "github.com/hyperledger/fabric-protos-go/peer"
    15  	. "github.com/onsi/ginkgo"
    16  	. "github.com/onsi/gomega"
    17  	"github.com/pkg/errors"
    18  	tm "github.com/stretchr/testify/mock"
    19  )
    20  
    21  var _ = Describe("FallbackPackageLocator", func() {
    22  	var (
    23  		cpl               *persistence.ChaincodePackageLocator
    24  		fakeLegacyLocator *mock.LegacyCCPackageLocator
    25  		fpl               *persistence.FallbackPackageLocator
    26  	)
    27  
    28  	BeforeEach(func() {
    29  		cpl = &persistence.ChaincodePackageLocator{
    30  			ChaincodeDir: "testdata",
    31  		}
    32  		fakeLegacyLocator = &mock.LegacyCCPackageLocator{}
    33  		fpl = &persistence.FallbackPackageLocator{
    34  			ChaincodePackageLocator: cpl,
    35  			LegacyCCPackageLocator:  fakeLegacyLocator,
    36  		}
    37  	})
    38  
    39  	Describe("GetChaincodePackage", func() {
    40  		It("gets the chaincode package metadata and stream", func() {
    41  			md, mdBytes, stream, err := fpl.GetChaincodePackage("good-package")
    42  			Expect(err).NotTo(HaveOccurred())
    43  			defer stream.Close()
    44  			Expect(md).To(Equal(&persistence.ChaincodePackageMetadata{
    45  				Type:  "Fake-Type",
    46  				Path:  "Fake-Path",
    47  				Label: "Real-Label",
    48  			}))
    49  			Expect(mdBytes).To(MatchJSON(`{"type":"Fake-Type","path":"Fake-Path","label":"Real-Label","extra_field":"extra-field-value"}`))
    50  			code, err := ioutil.ReadAll(stream)
    51  			Expect(err).NotTo(HaveOccurred())
    52  			Expect(code).To(Equal([]byte("package")))
    53  			Expect(fakeLegacyLocator.GetChaincodeDepSpecCallCount()).To(Equal(0))
    54  		})
    55  
    56  		Context("when the package has bad metadata", func() {
    57  			It("wraps and returns the error", func() {
    58  				_, _, _, err := fpl.GetChaincodePackage("bad-metadata")
    59  				Expect(err).To(MatchError(ContainSubstring("error retrieving chaincode package metadata 'bad-metadata'")))
    60  			})
    61  		})
    62  
    63  		Context("when the package has bad code", func() {
    64  			It("wraps and returns the error", func() {
    65  				_, _, _, err := fpl.GetChaincodePackage("missing-codepackage")
    66  				Expect(err).To(MatchError(ContainSubstring("error retrieving chaincode package code 'missing-codepackage'")))
    67  			})
    68  		})
    69  
    70  		Context("when the package is not in the new package store", func() {
    71  			BeforeEach(func() {
    72  				fakeLegacyLocator.GetChaincodeDepSpecReturns(
    73  					&pb.ChaincodeDeploymentSpec{
    74  						ChaincodeSpec: &pb.ChaincodeSpec{
    75  							ChaincodeId: &pb.ChaincodeID{
    76  								Path: "legacy-path",
    77  							},
    78  							Type: pb.ChaincodeSpec_GOLANG,
    79  						},
    80  						CodePackage: []byte("legacy-code"),
    81  					},
    82  					nil)
    83  			})
    84  
    85  			It("falls back to the legacy retriever", func() {
    86  				md, mdBytes, stream, err := fpl.GetChaincodePackage("legacy-package")
    87  				Expect(err).NotTo(HaveOccurred())
    88  				defer stream.Close()
    89  				Expect(md).To(Equal(&persistence.ChaincodePackageMetadata{
    90  					Path: "legacy-path",
    91  					Type: "GOLANG",
    92  				}))
    93  				Expect(mdBytes).To(MatchJSON(`{"type":"GOLANG","path":"legacy-path","label":""}`))
    94  				code, err := ioutil.ReadAll(stream)
    95  				Expect(err).NotTo(HaveOccurred())
    96  				Expect(code).To(Equal([]byte("legacy-code")))
    97  			})
    98  
    99  			Context("when the legacy provider returns an error", func() {
   100  				BeforeEach(func() {
   101  					fakeLegacyLocator.GetChaincodeDepSpecReturns(nil, errors.Errorf("fake-error"))
   102  				})
   103  
   104  				It("wraps and returns the error", func() {
   105  					_, _, _, err := fpl.GetChaincodePackage("legacy-package")
   106  					Expect(err).To(MatchError("could not get legacy chaincode package 'legacy-package': fake-error"))
   107  				})
   108  			})
   109  		})
   110  	})
   111  })
   112  
   113  var _ = Describe("ChaincodePackageParser", func() {
   114  	var (
   115  		mockMetaProvider *mock.MetadataProvider
   116  		ccpp             persistence.ChaincodePackageParser
   117  	)
   118  
   119  	BeforeEach(func() {
   120  		mockMetaProvider = &mock.MetadataProvider{}
   121  		mockMetaProvider.On("GetDBArtifacts", tm.Anything).Return([]byte("DB artefacts"), nil)
   122  
   123  		ccpp.MetadataProvider = mockMetaProvider
   124  	})
   125  
   126  	Describe("ParseChaincodePackage", func() {
   127  		It("parses a chaincode package", func() {
   128  			data, err := ioutil.ReadFile("testdata/good-package.tar.gz")
   129  			Expect(err).NotTo(HaveOccurred())
   130  
   131  			ccPackage, err := ccpp.Parse(data)
   132  			Expect(err).NotTo(HaveOccurred())
   133  			Expect(ccPackage.Metadata).To(Equal(&persistence.ChaincodePackageMetadata{
   134  				Type:  "Fake-Type",
   135  				Path:  "Fake-Path",
   136  				Label: "Real-Label",
   137  			}))
   138  			Expect(ccPackage.DBArtifacts).To(Equal([]byte("DB artefacts")))
   139  		})
   140  
   141  		Context("when the data is not gzipped", func() {
   142  			It("fails", func() {
   143  				_, err := ccpp.Parse([]byte("bad-data"))
   144  				Expect(err).To(MatchError("error reading as gzip stream: unexpected EOF"))
   145  			})
   146  		})
   147  
   148  		Context("when the retrieval of the DB metadata fails", func() {
   149  			BeforeEach(func() {
   150  				mockMetaProvider = &mock.MetadataProvider{}
   151  				mockMetaProvider.On("GetDBArtifacts", tm.Anything).Return(nil, errors.New("not good"))
   152  
   153  				ccpp.MetadataProvider = mockMetaProvider
   154  			})
   155  
   156  			It("fails", func() {
   157  				data, err := ioutil.ReadFile("testdata/good-package.tar.gz")
   158  				Expect(err).NotTo(HaveOccurred())
   159  
   160  				ccPackage, err := ccpp.Parse(data)
   161  				Expect(ccPackage).To(BeNil())
   162  				Expect(err).To(MatchError(ContainSubstring("error retrieving DB artifacts from code package")))
   163  			})
   164  		})
   165  
   166  		Context("when the chaincode package metadata is missing", func() {
   167  			It("fails", func() {
   168  				data, err := ioutil.ReadFile("testdata/missing-metadata.tar.gz")
   169  				Expect(err).NotTo(HaveOccurred())
   170  
   171  				_, err = ccpp.Parse(data)
   172  				Expect(err).To(MatchError("did not find any package metadata (missing metadata.json)"))
   173  			})
   174  		})
   175  
   176  		Context("when the chaincode package metadata is corrupt", func() {
   177  			It("fails", func() {
   178  				data, err := ioutil.ReadFile("testdata/bad-metadata.tar.gz")
   179  				Expect(err).NotTo(HaveOccurred())
   180  
   181  				_, err = ccpp.Parse(data)
   182  				Expect(err).To(MatchError("could not unmarshal metadata.json as json: invalid character '\\n' in string literal"))
   183  			})
   184  		})
   185  
   186  		Context("when the label is empty or missing", func() {
   187  			It("fails", func() {
   188  				data, err := ioutil.ReadFile("testdata/empty-label.tar.gz")
   189  				Expect(err).NotTo(HaveOccurred())
   190  
   191  				_, err = ccpp.Parse(data)
   192  				Expect(err.Error()).To(ContainSubstring("invalid label ''. Label must be non-empty, can only consist of alphanumerics, symbols from '.+-_', and can only begin with alphanumerics"))
   193  			})
   194  		})
   195  
   196  		Context("when the label contains forbidden characters", func() {
   197  			It("fails", func() {
   198  				data, err := ioutil.ReadFile("testdata/bad-label.tar.gz")
   199  				Expect(err).NotTo(HaveOccurred())
   200  
   201  				_, err = ccpp.Parse(data)
   202  				Expect(err.Error()).To(ContainSubstring("invalid label 'Bad-Label!'. Label must be non-empty, can only consist of alphanumerics, symbols from '.+-_', and can only begin with alphanumerics"))
   203  			})
   204  		})
   205  
   206  		Context("when the tar file is corrupted", func() {
   207  			It("fails", func() {
   208  				data, err := ioutil.ReadFile("testdata/corrupted-package.tar.gz")
   209  				Expect(err).NotTo(HaveOccurred())
   210  
   211  				_, err = ccpp.Parse(data)
   212  				Expect(err).To(MatchError("could not read Chaincode-Package-Metadata.json from tar: unexpected EOF"))
   213  			})
   214  		})
   215  
   216  		Context("when the tar has non-regular files", func() {
   217  			It("fails", func() {
   218  				data, err := ioutil.ReadFile("testdata/non-regular-file.tar.gz")
   219  				Expect(err).NotTo(HaveOccurred())
   220  
   221  				_, err = ccpp.Parse(data)
   222  				Expect(err).To(MatchError("tar entry code.tar.gz is not a regular file, type 50"))
   223  			})
   224  		})
   225  
   226  		Context("when the tar has a corrupt header entry", func() {
   227  			It("fails", func() {
   228  				data, err := ioutil.ReadFile("testdata/corrupted-header.tar.gz")
   229  				Expect(err).NotTo(HaveOccurred())
   230  
   231  				_, err = ccpp.Parse(data)
   232  				Expect(err).To(MatchError("error inspecting next tar header: flate: corrupt input before offset 86"))
   233  			})
   234  		})
   235  
   236  		Context("when the tar has too many entries", func() {
   237  			It("logs a warning but otherwise allows it", func() {
   238  				data, err := ioutil.ReadFile("testdata/too-many-files.tar.gz")
   239  				Expect(err).NotTo(HaveOccurred())
   240  
   241  				_, err = ccpp.Parse(data)
   242  				Expect(err).NotTo(HaveOccurred())
   243  			})
   244  		})
   245  
   246  		Context("when the tar is missing a code-package", func() {
   247  			It("fails", func() {
   248  				data, err := ioutil.ReadFile("testdata/missing-codepackage.tar.gz")
   249  				Expect(err).NotTo(HaveOccurred())
   250  
   251  				_, err = ccpp.Parse(data)
   252  				Expect(err).To(MatchError("did not find a code package inside the package"))
   253  			})
   254  		})
   255  	})
   256  })
   257  
   258  var _ = Describe("ChaincodePackageLocator", func() {
   259  	var locator *persistence.ChaincodePackageLocator
   260  
   261  	BeforeEach(func() {
   262  		locator = &persistence.ChaincodePackageLocator{
   263  			ChaincodeDir: "/fake-dir",
   264  		}
   265  	})
   266  
   267  	Describe("ChaincodePackageStreamer", func() {
   268  		It("creates a ChaincodePackageStreamer for the given packageID", func() {
   269  			streamer := locator.ChaincodePackageStreamer("test-package")
   270  			Expect(streamer).To(Equal(&persistence.ChaincodePackageStreamer{
   271  				PackagePath: "/fake-dir/test-package.tar.gz",
   272  			}))
   273  		})
   274  	})
   275  })
   276  
   277  var _ = Describe("ChaincodePackageStreamer", func() {
   278  	var streamer *persistence.ChaincodePackageStreamer
   279  
   280  	BeforeEach(func() {
   281  		streamer = &persistence.ChaincodePackageStreamer{
   282  			PackagePath: "testdata/good-package.tar.gz",
   283  		}
   284  	})
   285  
   286  	Describe("Metadata", func() {
   287  		It("reads the metadata from the package", func() {
   288  			md, err := streamer.Metadata()
   289  			Expect(err).NotTo(HaveOccurred())
   290  			Expect(md).To(Equal(&persistence.ChaincodePackageMetadata{
   291  				Type:  "Fake-Type",
   292  				Path:  "Fake-Path",
   293  				Label: "Real-Label",
   294  			}))
   295  		})
   296  
   297  		Context("when the metadata file cannot be found", func() {
   298  			BeforeEach(func() {
   299  				streamer.PackagePath = "testdata/missing-metadata.tar.gz"
   300  			})
   301  
   302  			It("wraps and returns the error", func() {
   303  				_, err := streamer.Metadata()
   304  				Expect(err).To(MatchError("could not get metadata file: did not find file 'metadata.json' in package"))
   305  			})
   306  		})
   307  
   308  		Context("when the metadata file cannot be parsed", func() {
   309  			BeforeEach(func() {
   310  				streamer.PackagePath = "testdata/bad-metadata.tar.gz"
   311  			})
   312  
   313  			It("wraps and returns the error", func() {
   314  				_, err := streamer.Metadata()
   315  				Expect(err).To(MatchError("could not parse metadata file: invalid character '\\n' in string literal"))
   316  			})
   317  		})
   318  	})
   319  
   320  	Describe("Code", func() {
   321  		It("reads a file from the package", func() {
   322  			code, err := streamer.Code()
   323  			Expect(err).NotTo(HaveOccurred())
   324  			codeBytes, err := ioutil.ReadAll(code)
   325  			code.Close()
   326  			Expect(err).NotTo(HaveOccurred())
   327  			Expect(codeBytes).To(Equal([]byte("package")))
   328  		})
   329  
   330  		Context("when the file cannot be found because the code is not a regular file", func() {
   331  			BeforeEach(func() {
   332  				streamer.PackagePath = "testdata/missing-codepackage.tar.gz"
   333  			})
   334  
   335  			It("wraps and returns the error", func() {
   336  				_, err := streamer.Code()
   337  				Expect(err).To(MatchError("could not get code package: did not find file 'code.tar.gz' in package"))
   338  			})
   339  		})
   340  	})
   341  
   342  	Describe("File", func() {
   343  		It("reads a file from the package", func() {
   344  			code, err := streamer.File("code.tar.gz")
   345  			Expect(err).NotTo(HaveOccurred())
   346  			codeBytes, err := ioutil.ReadAll(code)
   347  			code.Close()
   348  			Expect(err).NotTo(HaveOccurred())
   349  			Expect(codeBytes).To(Equal([]byte("package")))
   350  		})
   351  
   352  		Context("when the file is not a regular file", func() {
   353  			BeforeEach(func() {
   354  				streamer.PackagePath = "testdata/non-regular-file.tar.gz"
   355  			})
   356  
   357  			It("wraps and returns the error", func() {
   358  				_, err := streamer.File("code.tar.gz")
   359  				Expect(err).To(MatchError("tar entry code.tar.gz is not a regular file, type 50"))
   360  			})
   361  		})
   362  
   363  		Context("when the code cannot be found because the archive is corrupt", func() {
   364  			BeforeEach(func() {
   365  				streamer.PackagePath = "testdata/bad-archive.tar.gz"
   366  			})
   367  
   368  			It("wraps and returns the error", func() {
   369  				_, err := streamer.File("code.tar.gz")
   370  				Expect(err).To(MatchError("could not open chaincode package at 'testdata/bad-archive.tar.gz': open testdata/bad-archive.tar.gz: no such file or directory"))
   371  			})
   372  		})
   373  
   374  		Context("when the code cannot be found because the header is corrupt", func() {
   375  			BeforeEach(func() {
   376  				streamer.PackagePath = "testdata/corrupted-header.tar.gz"
   377  			})
   378  
   379  			It("wraps and returns the error", func() {
   380  				_, err := streamer.File("code.tar.gz")
   381  				Expect(err).To(MatchError("error inspecting next tar header: flate: corrupt input before offset 86"))
   382  			})
   383  		})
   384  
   385  		Context("when the code cannot be found because the gzip is corrupt", func() {
   386  			BeforeEach(func() {
   387  				streamer.PackagePath = "testdata/corrupted-gzip.tar.gz"
   388  			})
   389  
   390  			It("wraps and returns the error", func() {
   391  				_, err := streamer.File("code.tar.gz")
   392  				Expect(err).To(MatchError("error reading as gzip stream: unexpected EOF"))
   393  			})
   394  		})
   395  	})
   396  })