github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/core/common/ccprovider/ccinfocache_test.go (about)

     1  /*
     2  Copyright IBM Corp. 2017 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  		 http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package ccprovider
    18  
    19  import (
    20  	"archive/tar"
    21  	"bytes"
    22  	"compress/gzip"
    23  	"io/ioutil"
    24  	"path/filepath"
    25  	"testing"
    26  
    27  	"os"
    28  
    29  	"github.com/golang/protobuf/proto"
    30  	"github.com/hyperledger/fabric/core/container/util"
    31  	"github.com/hyperledger/fabric/protos/peer"
    32  	"github.com/stretchr/testify/assert"
    33  )
    34  
    35  func getDepSpec(name string, path string, version string, initArgs [][]byte) (*peer.ChaincodeDeploymentSpec, error) {
    36  	spec := &peer.ChaincodeSpec{Type: 1, ChaincodeId: &peer.ChaincodeID{Name: name, Path: path, Version: version}, Input: &peer.ChaincodeInput{Args: initArgs}}
    37  
    38  	codePackageBytes := bytes.NewBuffer(nil)
    39  	gz := gzip.NewWriter(codePackageBytes)
    40  	tw := tar.NewWriter(gz)
    41  
    42  	err := util.WriteBytesToPackage("src/garbage.go", []byte(name+path+version), tw)
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  
    47  	tw.Close()
    48  	gz.Close()
    49  
    50  	return &peer.ChaincodeDeploymentSpec{ChaincodeSpec: spec, CodePackage: codePackageBytes.Bytes()}, nil
    51  }
    52  
    53  func buildPackage(name string, path string, version string, initArgs [][]byte) (CCPackage, error) {
    54  	depSpec, err := getDepSpec(name, path, version, initArgs)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  
    59  	buf, err := proto.Marshal(depSpec)
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  	cccdspack := &CDSPackage{}
    64  	if _, err := cccdspack.InitFromBuffer(buf); err != nil {
    65  		return nil, err
    66  	}
    67  
    68  	return cccdspack, nil
    69  }
    70  
    71  type mockCCInfoFSStorageMgrImpl struct {
    72  	CCMap map[string]CCPackage
    73  }
    74  
    75  func (m *mockCCInfoFSStorageMgrImpl) GetChaincode(ccname string, ccversion string) (CCPackage, error) {
    76  	return m.CCMap[ccname+ccversion], nil
    77  }
    78  
    79  // here we test the cache implementation itself
    80  func TestCCInfoCache(t *testing.T) {
    81  	ccname := "foo"
    82  	ccver := "1.0"
    83  	ccpath := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02"
    84  
    85  	ccinfoFs := &mockCCInfoFSStorageMgrImpl{CCMap: map[string]CCPackage{}}
    86  	cccache := NewCCInfoCache(ccinfoFs)
    87  
    88  	// test the get side
    89  
    90  	// the cc data is not yet in the cache
    91  	_, err := cccache.GetChaincodeData(ccname, ccver)
    92  	assert.Error(t, err)
    93  
    94  	// put it in the file system
    95  	pack, err := buildPackage(ccname, ccpath, ccver, [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
    96  	assert.NoError(t, err)
    97  	ccinfoFs.CCMap[ccname+ccver] = pack
    98  
    99  	// expect it to be in the cache now
   100  	cd1, err := cccache.GetChaincodeData(ccname, ccver)
   101  	assert.NoError(t, err)
   102  
   103  	// it should still be in the cache
   104  	cd2, err := cccache.GetChaincodeData(ccname, ccver)
   105  	assert.NoError(t, err)
   106  
   107  	// they are not null
   108  	assert.NotNil(t, cd1)
   109  	assert.NotNil(t, cd2)
   110  
   111  	// test the put side now..
   112  	ccver = "2.0"
   113  	// put it in the file system
   114  	pack, err = buildPackage(ccname, ccpath, ccver, [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
   115  	assert.NoError(t, err)
   116  	ccinfoFs.CCMap[ccname+ccver] = pack
   117  
   118  	// create a dep spec to put
   119  	_, err = getDepSpec(ccname, ccpath, ccver, [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
   120  	assert.NoError(t, err)
   121  
   122  	// expect it to be cached
   123  	cd1, err = cccache.GetChaincodeData(ccname, ccver)
   124  	assert.NoError(t, err)
   125  
   126  	// it should still be in the cache
   127  	cd2, err = cccache.GetChaincodeData(ccname, ccver)
   128  	assert.NoError(t, err)
   129  
   130  	// they are not null
   131  	assert.NotNil(t, cd1)
   132  	assert.NotNil(t, cd2)
   133  }
   134  
   135  func TestPutChaincode(t *testing.T) {
   136  	ccname := ""
   137  	ccver := "1.0"
   138  	ccpath := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02"
   139  
   140  	ccinfoFs := &mockCCInfoFSStorageMgrImpl{CCMap: map[string]CCPackage{}}
   141  	NewCCInfoCache(ccinfoFs)
   142  
   143  	// Error case 1: ccname is empty
   144  	// create a dep spec to put
   145  	_, err := getDepSpec(ccname, ccpath, ccver, [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
   146  	assert.NoError(t, err)
   147  
   148  	// Error case 2: ccver is empty
   149  	ccname = "foo"
   150  	ccver = ""
   151  	_, err = getDepSpec(ccname, ccpath, ccver, [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
   152  	assert.NoError(t, err)
   153  
   154  	// Error case 3: ccfs.PutChainCode returns an error
   155  	ccinfoFs = &mockCCInfoFSStorageMgrImpl{CCMap: map[string]CCPackage{}}
   156  	NewCCInfoCache(ccinfoFs)
   157  
   158  	ccname = "foo"
   159  	ccver = "1.0"
   160  	_, err = getDepSpec(ccname, ccpath, ccver, [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
   161  	assert.NoError(t, err)
   162  }
   163  
   164  // here we test the peer's built-in cache after enabling it
   165  func TestCCInfoFSPeerInstance(t *testing.T) {
   166  	ccname := "bar"
   167  	ccver := "1.0"
   168  	ccpath := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02"
   169  
   170  	// the cc data is not yet in the cache
   171  	_, err := GetChaincodeFromFS(ccname, ccver)
   172  	assert.Error(t, err)
   173  
   174  	// create a dep spec to put
   175  	ds, err := getDepSpec(ccname, ccpath, ccver, [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
   176  	assert.NoError(t, err)
   177  
   178  	// put it
   179  	err = PutChaincodeIntoFS(ds)
   180  	assert.NoError(t, err)
   181  
   182  	// Get all installed chaincodes, it should not return 0 chain codes
   183  	resp, err := GetInstalledChaincodes()
   184  	assert.NoError(t, err)
   185  	assert.NotNil(t, resp)
   186  	assert.NotZero(t, len(resp.Chaincodes), "GetInstalledChaincodes should not have returned 0 chain codes")
   187  
   188  	//get chaincode data
   189  	_, err = GetChaincodeData(ccname, ccver)
   190  	assert.NoError(t, err)
   191  }
   192  
   193  func TestGetInstalledChaincodesErrorPaths(t *testing.T) {
   194  	// Get the existing chaincode install path value and set it
   195  	// back after we are done with the test
   196  	cip := chaincodeInstallPath
   197  	defer SetChaincodesPath(cip)
   198  
   199  	// Create a temp dir and remove it at the end
   200  	dir, err := ioutil.TempDir(os.TempDir(), "chaincodes")
   201  	assert.NoError(t, err)
   202  	defer os.RemoveAll(dir)
   203  
   204  	// Set the above created directory as the chain code install path
   205  	SetChaincodesPath(dir)
   206  	err = ioutil.WriteFile(filepath.Join(dir, "idontexist.1.0"), []byte("test"), 0777)
   207  	assert.NoError(t, err)
   208  	resp, err := GetInstalledChaincodes()
   209  	assert.NoError(t, err)
   210  	assert.Equal(t, 0, len(resp.Chaincodes),
   211  		"Expected 0 chain codes but GetInstalledChaincodes returned %s chain codes", len(resp.Chaincodes))
   212  }
   213  
   214  func TestNewCCContext(t *testing.T) {
   215  	ccctx := NewCCContext("foo", "foo", "1.0", "", false, nil, nil)
   216  	assert.NotNil(t, ccctx)
   217  	canName := ccctx.GetCanonicalName()
   218  	assert.NotEmpty(t, canName)
   219  
   220  	assert.Panics(t, func() {
   221  		NewCCContext("foo", "foo", "", "", false, nil, nil)
   222  	}, "NewCCContext should have paniced if version is empty")
   223  
   224  	ccctx = &CCContext{"foo", "foo", "1.0", "", false, nil, nil, ""}
   225  	assert.Panics(t, func() {
   226  		ccctx.GetCanonicalName()
   227  	}, "GetConnonicalName should have paniced if cannonical name is empty")
   228  }
   229  
   230  func TestChaincodePackageExists(t *testing.T) {
   231  	_, err := ChaincodePackageExists("foo1", "1.0")
   232  	assert.Error(t, err)
   233  }
   234  
   235  func TestSetChaincodesPath(t *testing.T) {
   236  	dir, err := ioutil.TempDir(os.TempDir(), "setchaincodes")
   237  	if err != nil {
   238  		assert.Fail(t, err.Error(), "Unable to create temp dir")
   239  	}
   240  	defer os.RemoveAll(dir)
   241  	t.Logf("created temp dir %s", dir)
   242  
   243  	// Get the existing chaincode install path value and set it
   244  	// back after we are done with the test
   245  	cip := chaincodeInstallPath
   246  	defer SetChaincodesPath(cip)
   247  
   248  	f, err := ioutil.TempFile(dir, "chaincodes")
   249  	assert.NoError(t, err)
   250  	assert.Panics(t, func() {
   251  		SetChaincodesPath(f.Name())
   252  	}, "SetChaincodesPath should have paniced if a file is passed to it")
   253  
   254  	// Following code works on mac but does not work in CI
   255  	// // Make the directory read only
   256  	// err = os.Chmod(dir, 0444)
   257  	// assert.NoError(t, err)
   258  	// cdir := filepath.Join(dir, "chaincodesdir")
   259  	// assert.Panics(t, func() {
   260  	// 	SetChaincodesPath(cdir)
   261  	// }, "SetChaincodesPath should have paniced if it is not able to stat the dir")
   262  
   263  	// // Make the directory read and execute
   264  	// err = os.Chmod(dir, 0555)
   265  	// assert.NoError(t, err)
   266  	// assert.Panics(t, func() {
   267  	// 	SetChaincodesPath(cdir)
   268  	// }, "SetChaincodesPath should have paniced if it is not able to create the dir")
   269  }
   270  
   271  var ccinfocachetestpath = "/tmp/ccinfocachetest"
   272  
   273  func TestMain(m *testing.M) {
   274  	os.RemoveAll(ccinfocachetestpath)
   275  
   276  	SetChaincodesPath(ccinfocachetestpath)
   277  	rc := m.Run()
   278  	os.RemoveAll(ccinfocachetestpath)
   279  	os.Exit(rc)
   280  }