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 }