github.com/yacovm/fabric@v2.0.0-alpha.0.20191128145320-c5d4087dc723+incompatible/internal/peer/lifecycle/chaincode/package_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  	"archive/tar"
    11  	"compress/gzip"
    12  	"encoding/json"
    13  	"io"
    14  	"os"
    15  	"path/filepath"
    16  
    17  	"github.com/hyperledger/fabric/internal/peer/lifecycle/chaincode"
    18  	"github.com/hyperledger/fabric/internal/peer/lifecycle/chaincode/mock"
    19  	"github.com/pkg/errors"
    20  	"github.com/spf13/cobra"
    21  
    22  	. "github.com/onsi/ginkgo"
    23  	. "github.com/onsi/gomega"
    24  	"github.com/onsi/gomega/gbytes"
    25  )
    26  
    27  var _ = Describe("Package", func() {
    28  	Describe("Packager", func() {
    29  		var (
    30  			mockPlatformRegistry *mock.PlatformRegistry
    31  			mockWriter           *mock.Writer
    32  			input                *chaincode.PackageInput
    33  			packager             *chaincode.Packager
    34  		)
    35  
    36  		BeforeEach(func() {
    37  			mockPlatformRegistry = &mock.PlatformRegistry{}
    38  			mockPlatformRegistry.NormalizePathReturns("normalizedPath", nil)
    39  
    40  			input = &chaincode.PackageInput{
    41  				OutputFile: "testDir/testPackage",
    42  				Path:       "testPath",
    43  				Type:       "testType",
    44  				Label:      "testLabel",
    45  			}
    46  
    47  			mockWriter = &mock.Writer{}
    48  
    49  			packager = &chaincode.Packager{
    50  				PlatformRegistry: mockPlatformRegistry,
    51  				Writer:           mockWriter,
    52  				Input:            input,
    53  			}
    54  		})
    55  
    56  		It("packages chaincodes", func() {
    57  			err := packager.Package()
    58  			Expect(err).NotTo(HaveOccurred())
    59  
    60  			Expect(mockPlatformRegistry.NormalizePathCallCount()).To(Equal(1))
    61  			ccType, path := mockPlatformRegistry.NormalizePathArgsForCall(0)
    62  			Expect(ccType).To(Equal("TESTTYPE"))
    63  			Expect(path).To(Equal("testPath"))
    64  
    65  			Expect(mockPlatformRegistry.GetDeploymentPayloadCallCount()).To(Equal(1))
    66  			ccType, path = mockPlatformRegistry.GetDeploymentPayloadArgsForCall(0)
    67  			Expect(ccType).To(Equal("TESTTYPE"))
    68  			Expect(path).To(Equal("testPath"))
    69  
    70  			Expect(mockWriter.WriteFileCallCount()).To(Equal(1))
    71  			dir, name, pkgTarGzBytes := mockWriter.WriteFileArgsForCall(0)
    72  			wd, err := os.Getwd()
    73  			Expect(err).NotTo(HaveOccurred())
    74  			Expect(dir).To(Equal(filepath.Join(wd, "testDir")))
    75  			Expect(name).To(Equal("testPackage"))
    76  			Expect(pkgTarGzBytes).NotTo(BeNil())
    77  
    78  			metadata, err := readMetadataFromBytes(pkgTarGzBytes)
    79  			Expect(err).NotTo(HaveOccurred())
    80  			Expect(metadata).To(Equal(&chaincode.PackageMetadata{
    81  				Path:  "normalizedPath",
    82  				Type:  "testType",
    83  				Label: "testLabel",
    84  			}))
    85  		})
    86  
    87  		Context("when the path is not provided", func() {
    88  			BeforeEach(func() {
    89  				input.Path = ""
    90  			})
    91  
    92  			It("returns an error", func() {
    93  				err := packager.Package()
    94  				Expect(err).To(MatchError("chaincode path must be specified"))
    95  			})
    96  		})
    97  
    98  		Context("when the type is not provided", func() {
    99  			BeforeEach(func() {
   100  				input.Type = ""
   101  			})
   102  
   103  			It("returns an error", func() {
   104  				err := packager.Package()
   105  				Expect(err).To(MatchError("chaincode language must be specified"))
   106  			})
   107  		})
   108  
   109  		Context("when the output file is not provided", func() {
   110  			BeforeEach(func() {
   111  				input.OutputFile = ""
   112  			})
   113  
   114  			It("returns an error", func() {
   115  				err := packager.Package()
   116  				Expect(err).To(MatchError("output file must be specified"))
   117  			})
   118  		})
   119  
   120  		Context("when the label is not provided", func() {
   121  			BeforeEach(func() {
   122  				input.Label = ""
   123  			})
   124  
   125  			It("returns an error", func() {
   126  				err := packager.Package()
   127  				Expect(err).To(MatchError("package label must be specified"))
   128  			})
   129  		})
   130  
   131  		Context("when the platform registry fails to normalize the path", func() {
   132  			BeforeEach(func() {
   133  				mockPlatformRegistry.NormalizePathReturns("", errors.New("cortado"))
   134  			})
   135  
   136  			It("returns an error", func() {
   137  				err := packager.Package()
   138  				Expect(err).To(MatchError("failed to normalize chaincode path: cortado"))
   139  			})
   140  		})
   141  
   142  		Context("when the platform registry fails to get the deployment payload", func() {
   143  			BeforeEach(func() {
   144  				mockPlatformRegistry.GetDeploymentPayloadReturns(nil, errors.New("americano"))
   145  			})
   146  
   147  			It("returns an error", func() {
   148  				err := packager.Package()
   149  				Expect(err).To(MatchError("error getting chaincode bytes: americano"))
   150  			})
   151  		})
   152  
   153  		Context("when writing the file fails", func() {
   154  			BeforeEach(func() {
   155  				mockWriter.WriteFileReturns(errors.New("espresso"))
   156  			})
   157  
   158  			It("returns an error", func() {
   159  				err := packager.Package()
   160  				Expect(err).To(MatchError("error writing chaincode package to testDir/testPackage: espresso"))
   161  			})
   162  		})
   163  	})
   164  
   165  	Describe("PackageCmd", func() {
   166  		var (
   167  			packageCmd *cobra.Command
   168  		)
   169  
   170  		BeforeEach(func() {
   171  			packageCmd = chaincode.PackageCmd(nil)
   172  			packageCmd.SetArgs([]string{
   173  				"testPackage",
   174  				"--path=testPath",
   175  				"--lang=golang",
   176  				"--label=testLabel",
   177  			})
   178  		})
   179  
   180  		It("sets up the packager and attempts to package the chaincode", func() {
   181  			err := packageCmd.Execute()
   182  			Expect(err).To(MatchError(ContainSubstring("error getting chaincode bytes")))
   183  		})
   184  
   185  		Context("when more than one argument is provided", func() {
   186  			BeforeEach(func() {
   187  				packageCmd = chaincode.PackageCmd(nil)
   188  				packageCmd.SetArgs([]string{
   189  					"testPackage",
   190  					"whatthe",
   191  				})
   192  			})
   193  
   194  			It("returns an error", func() {
   195  				err := packageCmd.Execute()
   196  				Expect(err).To(MatchError("invalid number of args. expected only the output file"))
   197  			})
   198  		})
   199  
   200  		Context("when no argument is provided", func() {
   201  			BeforeEach(func() {
   202  				packageCmd = chaincode.PackageCmd(nil)
   203  				packageCmd.SetArgs([]string{})
   204  			})
   205  
   206  			It("returns an error", func() {
   207  				err := packageCmd.Execute()
   208  				Expect(err).To(MatchError("invalid number of args. expected only the output file"))
   209  			})
   210  		})
   211  	})
   212  })
   213  
   214  func readMetadataFromBytes(pkgTarGzBytes []byte) (*chaincode.PackageMetadata, error) {
   215  	buffer := gbytes.BufferWithBytes(pkgTarGzBytes)
   216  	gzr, err := gzip.NewReader(buffer)
   217  	Expect(err).NotTo(HaveOccurred())
   218  	defer gzr.Close()
   219  	tr := tar.NewReader(gzr)
   220  	for {
   221  		header, err := tr.Next()
   222  		if err == io.EOF {
   223  			break
   224  		}
   225  		if err != nil {
   226  			return nil, err
   227  		}
   228  		if header.Name == "metadata.json" {
   229  			jsonDecoder := json.NewDecoder(tr)
   230  			metadata := &chaincode.PackageMetadata{}
   231  			err := jsonDecoder.Decode(metadata)
   232  			return metadata, err
   233  		}
   234  	}
   235  	return nil, errors.New("metadata.json not found")
   236  }