github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/common/ccprovider/ccinfocache_test.go (about) 1 /* 2 Copyright hechain. 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/hechain20/hechain/bccsp/sw" 30 "github.com/hyperledger/fabric-protos-go/peer" 31 "github.com/stretchr/testify/require" 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: 0o100644, 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 require.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 require.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 require.NoError(t, err) 112 113 // it should still be in the cache 114 cd2, err := cccache.GetChaincodeData("foo:1.0") 115 require.NoError(t, err) 116 117 // they are not null 118 require.NotNil(t, cd1) 119 require.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 require.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 require.NoError(t, err) 129 130 // expect it to be cached 131 cd1, err = cccache.GetChaincodeData("foo:2.0") 132 require.NoError(t, err) 133 134 // it should still be in the cache 135 cd2, err = cccache.GetChaincodeData("foo:2.0") 136 require.NoError(t, err) 137 138 // they are not null 139 require.NotNil(t, cd1) 140 require.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 require.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 require.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 require.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 require.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 require.NoError(t, err) 185 186 // put it 187 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 188 require.NoError(t, err) 189 ccinfoFSImpl := &CCInfoFSImpl{GetHasher: cryptoProvider} 190 _, err = ccinfoFSImpl.PutChaincode(ds) 191 require.NoError(t, err) 192 193 // Get all installed chaincodes, it should not return 0 chaincodes 194 resp, err := GetInstalledChaincodes() 195 require.NoError(t, err) 196 require.NotNil(t, resp) 197 require.NotZero(t, len(resp.Chaincodes), "GetInstalledChaincodes should not have returned 0 chaincodes") 198 199 // get chaincode data 200 _, err = GetChaincodeData("bar:1.0") 201 require.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 require.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"), 0o777) 218 require.NoError(t, err) 219 resp, err := GetInstalledChaincodes() 220 require.NoError(t, err) 221 require.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 require.Error(t, err) 228 } 229 230 func TestSetChaincodesPath(t *testing.T) { 231 dir, err := ioutil.TempDir(os.TempDir(), "setchaincodes") 232 if err != nil { 233 require.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 require.NoError(t, err) 245 require.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 }