github.com/renegr87/renegr87@v2.1.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 }