github.com/kaituanwang/hyperledger@v2.0.1+incompatible/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  	"os"
    25  	"path/filepath"
    26  	"testing"
    27  
    28  	"github.com/golang/protobuf/proto"
    29  	"github.com/hyperledger/fabric-protos-go/peer"
    30  	"github.com/hyperledger/fabric/bccsp/sw"
    31  	"github.com/stretchr/testify/assert"
    32  )
    33  
    34  func getDepSpec(name string, path string, version string, initArgs [][]byte) (*peer.ChaincodeDeploymentSpec, error) {
    35  	spec := &peer.ChaincodeSpec{Type: 1, ChaincodeId: &peer.ChaincodeID{Name: name, Path: path, Version: version}, Input: &peer.ChaincodeInput{Args: initArgs}}
    36  
    37  	codePackageBytes := bytes.NewBuffer(nil)
    38  	gz := gzip.NewWriter(codePackageBytes)
    39  	tw := tar.NewWriter(gz)
    40  
    41  	payload := []byte(name + path + version)
    42  	err := tw.WriteHeader(&tar.Header{
    43  		Name: "src/garbage.go",
    44  		Size: int64(len(payload)),
    45  		Mode: 0100644,
    46  	})
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	_, err = tw.Write(payload)
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  
    56  	tw.Close()
    57  	gz.Close()
    58  
    59  	return &peer.ChaincodeDeploymentSpec{ChaincodeSpec: spec, CodePackage: codePackageBytes.Bytes()}, nil
    60  }
    61  
    62  func buildPackage(name string, path string, version string, initArgs [][]byte) (CCPackage, error) {
    63  	depSpec, err := getDepSpec(name, path, version, initArgs)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  
    68  	buf, err := proto.Marshal(depSpec)
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  
    73  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
    74  	if err != nil {
    75  		return nil, err
    76  	}
    77  	cccdspack := &CDSPackage{GetHasher: cryptoProvider}
    78  	if _, err := cccdspack.InitFromBuffer(buf); err != nil {
    79  		return nil, err
    80  	}
    81  
    82  	return cccdspack, nil
    83  }
    84  
    85  type mockCCInfoFSStorageMgrImpl struct {
    86  	CCMap map[string]CCPackage
    87  }
    88  
    89  func (m *mockCCInfoFSStorageMgrImpl) GetChaincode(ccNameVersion string) (CCPackage, error) {
    90  	return m.CCMap[ccNameVersion], nil
    91  }
    92  
    93  // here we test the cache implementation itself
    94  func TestCCInfoCache(t *testing.T) {
    95  	ccinfoFs := &mockCCInfoFSStorageMgrImpl{CCMap: map[string]CCPackage{}}
    96  	cccache := NewCCInfoCache(ccinfoFs)
    97  
    98  	// test the get side
    99  
   100  	// the cc data is not yet in the cache
   101  	_, err := cccache.GetChaincodeData("foo:1.0")
   102  	assert.Error(t, err)
   103  
   104  	// put it in the file system
   105  	pack, err := buildPackage("foo", "mychaincode", "1.0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
   106  	assert.NoError(t, err)
   107  	ccinfoFs.CCMap["foo:1.0"] = pack
   108  
   109  	// expect it to be in the cache now
   110  	cd1, err := cccache.GetChaincodeData("foo:1.0")
   111  	assert.NoError(t, err)
   112  
   113  	// it should still be in the cache
   114  	cd2, err := cccache.GetChaincodeData("foo:1.0")
   115  	assert.NoError(t, err)
   116  
   117  	// they are not null
   118  	assert.NotNil(t, cd1)
   119  	assert.NotNil(t, cd2)
   120  
   121  	// put it in the file system
   122  	pack, err = buildPackage("foo", "mychaincode", "2.0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
   123  	assert.NoError(t, err)
   124  	ccinfoFs.CCMap["foo:2.0"] = pack
   125  
   126  	// create a dep spec to put
   127  	_, err = getDepSpec("foo", "mychaincode", "2.0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
   128  	assert.NoError(t, err)
   129  
   130  	// expect it to be cached
   131  	cd1, err = cccache.GetChaincodeData("foo:2.0")
   132  	assert.NoError(t, err)
   133  
   134  	// it should still be in the cache
   135  	cd2, err = cccache.GetChaincodeData("foo:2.0")
   136  	assert.NoError(t, err)
   137  
   138  	// they are not null
   139  	assert.NotNil(t, cd1)
   140  	assert.NotNil(t, cd2)
   141  }
   142  
   143  func TestPutChaincode(t *testing.T) {
   144  	ccname := ""
   145  	ccver := "1.0"
   146  	ccpath := "mychaincode"
   147  
   148  	ccinfoFs := &mockCCInfoFSStorageMgrImpl{CCMap: map[string]CCPackage{}}
   149  	NewCCInfoCache(ccinfoFs)
   150  
   151  	// Error case 1: ccname is empty
   152  	// create a dep spec to put
   153  	_, err := getDepSpec(ccname, ccpath, ccver, [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
   154  	assert.NoError(t, err)
   155  
   156  	// Error case 2: ccver is empty
   157  	ccname = "foo"
   158  	ccver = ""
   159  	_, err = getDepSpec(ccname, ccpath, ccver, [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
   160  	assert.NoError(t, err)
   161  
   162  	// Error case 3: ccfs.PutChainCode returns an error
   163  	ccinfoFs = &mockCCInfoFSStorageMgrImpl{CCMap: map[string]CCPackage{}}
   164  	NewCCInfoCache(ccinfoFs)
   165  
   166  	ccname = "foo"
   167  	ccver = "1.0"
   168  	_, err = getDepSpec(ccname, ccpath, ccver, [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
   169  	assert.NoError(t, err)
   170  }
   171  
   172  // here we test the peer's built-in cache after enabling it
   173  func TestCCInfoFSPeerInstance(t *testing.T) {
   174  	ccname := "bar"
   175  	ccver := "1.0"
   176  	ccpath := "mychaincode"
   177  
   178  	// the cc data is not yet in the cache
   179  	_, err := GetChaincodeFromFS("bar:1.0")
   180  	assert.Error(t, err)
   181  
   182  	// create a dep spec to put
   183  	ds, err := getDepSpec(ccname, ccpath, ccver, [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
   184  	assert.NoError(t, err)
   185  
   186  	// put it
   187  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   188  	assert.NoError(t, err)
   189  	ccinfoFSImpl := &CCInfoFSImpl{GetHasher: cryptoProvider}
   190  	_, err = ccinfoFSImpl.PutChaincode(ds)
   191  	assert.NoError(t, err)
   192  
   193  	// Get all installed chaincodes, it should not return 0 chaincodes
   194  	resp, err := GetInstalledChaincodes()
   195  	assert.NoError(t, err)
   196  	assert.NotNil(t, resp)
   197  	assert.NotZero(t, len(resp.Chaincodes), "GetInstalledChaincodes should not have returned 0 chaincodes")
   198  
   199  	//get chaincode data
   200  	_, err = GetChaincodeData("bar:1.0")
   201  	assert.NoError(t, err)
   202  }
   203  
   204  func TestGetInstalledChaincodesErrorPaths(t *testing.T) {
   205  	// Get the existing chaincode install path value and set it
   206  	// back after we are done with the test
   207  	cip := chaincodeInstallPath
   208  	defer SetChaincodesPath(cip)
   209  
   210  	// Create a temp dir and remove it at the end
   211  	dir, err := ioutil.TempDir(os.TempDir(), "chaincodes")
   212  	assert.NoError(t, err)
   213  	defer os.RemoveAll(dir)
   214  
   215  	// Set the above created directory as the chaincode install path
   216  	SetChaincodesPath(dir)
   217  	err = ioutil.WriteFile(filepath.Join(dir, "idontexist.1.0"), []byte("test"), 0777)
   218  	assert.NoError(t, err)
   219  	resp, err := GetInstalledChaincodes()
   220  	assert.NoError(t, err)
   221  	assert.Equal(t, 0, len(resp.Chaincodes),
   222  		"Expected 0 chaincodes but GetInstalledChaincodes returned %s chaincodes", len(resp.Chaincodes))
   223  }
   224  
   225  func TestChaincodePackageExists(t *testing.T) {
   226  	_, err := ChaincodePackageExists("foo1", "1.0")
   227  	assert.Error(t, err)
   228  }
   229  
   230  func TestSetChaincodesPath(t *testing.T) {
   231  	dir, err := ioutil.TempDir(os.TempDir(), "setchaincodes")
   232  	if err != nil {
   233  		assert.Fail(t, err.Error(), "Unable to create temp dir")
   234  	}
   235  	defer os.RemoveAll(dir)
   236  	t.Logf("created temp dir %s", dir)
   237  
   238  	// Get the existing chaincode install path value and set it
   239  	// back after we are done with the test
   240  	cip := chaincodeInstallPath
   241  	defer SetChaincodesPath(cip)
   242  
   243  	f, err := ioutil.TempFile(dir, "chaincodes")
   244  	assert.NoError(t, err)
   245  	assert.Panics(t, func() {
   246  		SetChaincodesPath(f.Name())
   247  	}, "SetChaincodesPath should have paniced if a file is passed to it")
   248  
   249  	// Following code works on mac but does not work in CI
   250  	// // Make the directory read only
   251  	// err = os.Chmod(dir, 0444)
   252  	// assert.NoError(t, err)
   253  	// cdir := filepath.Join(dir, "chaincodesdir")
   254  	// assert.Panics(t, func() {
   255  	// 	SetChaincodesPath(cdir)
   256  	// }, "SetChaincodesPath should have paniced if it is not able to stat the dir")
   257  
   258  	// // Make the directory read and execute
   259  	// err = os.Chmod(dir, 0555)
   260  	// assert.NoError(t, err)
   261  	// assert.Panics(t, func() {
   262  	// 	SetChaincodesPath(cdir)
   263  	// }, "SetChaincodesPath should have paniced if it is not able to create the dir")
   264  }
   265  
   266  var ccinfocachetestpath = "/tmp/ccinfocachetest"
   267  
   268  func TestMain(m *testing.M) {
   269  	os.RemoveAll(ccinfocachetestpath)
   270  
   271  	SetChaincodesPath(ccinfocachetestpath)
   272  	rc := m.Run()
   273  	os.RemoveAll(ccinfocachetestpath)
   274  	os.Exit(rc)
   275  }