github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/chaincode/persistence/chaincode_package_test.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package persistence_test 8 9 import ( 10 "io/ioutil" 11 12 "github.com/hechain20/hechain/core/chaincode/persistence" 13 "github.com/hechain20/hechain/core/chaincode/persistence/mock" 14 pb "github.com/hyperledger/fabric-protos-go/peer" 15 . "github.com/onsi/ginkgo" 16 . "github.com/onsi/gomega" 17 "github.com/pkg/errors" 18 tm "github.com/stretchr/testify/mock" 19 ) 20 21 var _ = Describe("FallbackPackageLocator", func() { 22 var ( 23 cpl *persistence.ChaincodePackageLocator 24 fakeLegacyLocator *mock.LegacyCCPackageLocator 25 fpl *persistence.FallbackPackageLocator 26 ) 27 28 BeforeEach(func() { 29 cpl = &persistence.ChaincodePackageLocator{ 30 ChaincodeDir: "testdata", 31 } 32 fakeLegacyLocator = &mock.LegacyCCPackageLocator{} 33 fpl = &persistence.FallbackPackageLocator{ 34 ChaincodePackageLocator: cpl, 35 LegacyCCPackageLocator: fakeLegacyLocator, 36 } 37 }) 38 39 Describe("GetChaincodePackage", func() { 40 It("gets the chaincode package metadata and stream", func() { 41 md, mdBytes, stream, err := fpl.GetChaincodePackage("good-package") 42 Expect(err).NotTo(HaveOccurred()) 43 defer stream.Close() 44 Expect(md).To(Equal(&persistence.ChaincodePackageMetadata{ 45 Type: "Fake-Type", 46 Path: "Fake-Path", 47 Label: "Real-Label", 48 })) 49 Expect(mdBytes).To(MatchJSON(`{"type":"Fake-Type","path":"Fake-Path","label":"Real-Label","extra_field":"extra-field-value"}`)) 50 code, err := ioutil.ReadAll(stream) 51 Expect(err).NotTo(HaveOccurred()) 52 Expect(code).To(Equal([]byte("package"))) 53 Expect(fakeLegacyLocator.GetChaincodeDepSpecCallCount()).To(Equal(0)) 54 }) 55 56 Context("when the package has bad metadata", func() { 57 It("wraps and returns the error", func() { 58 _, _, _, err := fpl.GetChaincodePackage("bad-metadata") 59 Expect(err).To(MatchError(ContainSubstring("error retrieving chaincode package metadata 'bad-metadata'"))) 60 }) 61 }) 62 63 Context("when the package has bad code", func() { 64 It("wraps and returns the error", func() { 65 _, _, _, err := fpl.GetChaincodePackage("missing-codepackage") 66 Expect(err).To(MatchError(ContainSubstring("error retrieving chaincode package code 'missing-codepackage'"))) 67 }) 68 }) 69 70 Context("when the package is not in the new package store", func() { 71 BeforeEach(func() { 72 fakeLegacyLocator.GetChaincodeDepSpecReturns( 73 &pb.ChaincodeDeploymentSpec{ 74 ChaincodeSpec: &pb.ChaincodeSpec{ 75 ChaincodeId: &pb.ChaincodeID{ 76 Path: "legacy-path", 77 }, 78 Type: pb.ChaincodeSpec_GOLANG, 79 }, 80 CodePackage: []byte("legacy-code"), 81 }, 82 nil) 83 }) 84 85 It("falls back to the legacy retriever", func() { 86 md, mdBytes, stream, err := fpl.GetChaincodePackage("legacy-package") 87 Expect(err).NotTo(HaveOccurred()) 88 defer stream.Close() 89 Expect(md).To(Equal(&persistence.ChaincodePackageMetadata{ 90 Path: "legacy-path", 91 Type: "GOLANG", 92 })) 93 Expect(mdBytes).To(MatchJSON(`{"type":"GOLANG","path":"legacy-path","label":""}`)) 94 code, err := ioutil.ReadAll(stream) 95 Expect(err).NotTo(HaveOccurred()) 96 Expect(code).To(Equal([]byte("legacy-code"))) 97 }) 98 99 Context("when the legacy provider returns an error", func() { 100 BeforeEach(func() { 101 fakeLegacyLocator.GetChaincodeDepSpecReturns(nil, errors.Errorf("fake-error")) 102 }) 103 104 It("wraps and returns the error", func() { 105 _, _, _, err := fpl.GetChaincodePackage("legacy-package") 106 Expect(err).To(MatchError("could not get legacy chaincode package 'legacy-package': fake-error")) 107 }) 108 }) 109 }) 110 }) 111 }) 112 113 var _ = Describe("ChaincodePackageParser", func() { 114 var ( 115 mockMetaProvider *mock.MetadataProvider 116 ccpp persistence.ChaincodePackageParser 117 ) 118 119 BeforeEach(func() { 120 mockMetaProvider = &mock.MetadataProvider{} 121 mockMetaProvider.On("GetDBArtifacts", tm.Anything).Return([]byte("DB artefacts"), nil) 122 123 ccpp.MetadataProvider = mockMetaProvider 124 }) 125 126 Describe("ParseChaincodePackage", func() { 127 It("parses a chaincode package", func() { 128 data, err := ioutil.ReadFile("testdata/good-package.tar.gz") 129 Expect(err).NotTo(HaveOccurred()) 130 131 ccPackage, err := ccpp.Parse(data) 132 Expect(err).NotTo(HaveOccurred()) 133 Expect(ccPackage.Metadata).To(Equal(&persistence.ChaincodePackageMetadata{ 134 Type: "Fake-Type", 135 Path: "Fake-Path", 136 Label: "Real-Label", 137 })) 138 Expect(ccPackage.DBArtifacts).To(Equal([]byte("DB artefacts"))) 139 }) 140 141 Context("when the data is not gzipped", func() { 142 It("fails", func() { 143 _, err := ccpp.Parse([]byte("bad-data")) 144 Expect(err).To(MatchError("error reading as gzip stream: unexpected EOF")) 145 }) 146 }) 147 148 Context("when the retrieval of the DB metadata fails", func() { 149 BeforeEach(func() { 150 mockMetaProvider = &mock.MetadataProvider{} 151 mockMetaProvider.On("GetDBArtifacts", tm.Anything).Return(nil, errors.New("not good")) 152 153 ccpp.MetadataProvider = mockMetaProvider 154 }) 155 156 It("fails", func() { 157 data, err := ioutil.ReadFile("testdata/good-package.tar.gz") 158 Expect(err).NotTo(HaveOccurred()) 159 160 ccPackage, err := ccpp.Parse(data) 161 Expect(ccPackage).To(BeNil()) 162 Expect(err).To(MatchError(ContainSubstring("error retrieving DB artifacts from code package"))) 163 }) 164 }) 165 166 Context("when the chaincode package metadata is missing", func() { 167 It("fails", func() { 168 data, err := ioutil.ReadFile("testdata/missing-metadata.tar.gz") 169 Expect(err).NotTo(HaveOccurred()) 170 171 _, err = ccpp.Parse(data) 172 Expect(err).To(MatchError("did not find any package metadata (missing metadata.json)")) 173 }) 174 }) 175 176 Context("when the chaincode package metadata is corrupt", func() { 177 It("fails", func() { 178 data, err := ioutil.ReadFile("testdata/bad-metadata.tar.gz") 179 Expect(err).NotTo(HaveOccurred()) 180 181 _, err = ccpp.Parse(data) 182 Expect(err).To(MatchError("could not unmarshal metadata.json as json: invalid character '\\n' in string literal")) 183 }) 184 }) 185 186 Context("when the label is empty or missing", func() { 187 It("fails", func() { 188 data, err := ioutil.ReadFile("testdata/empty-label.tar.gz") 189 Expect(err).NotTo(HaveOccurred()) 190 191 _, err = ccpp.Parse(data) 192 Expect(err.Error()).To(ContainSubstring("invalid label ''. Label must be non-empty, can only consist of alphanumerics, symbols from '.+-_', and can only begin with alphanumerics")) 193 }) 194 }) 195 196 Context("when the label contains forbidden characters", func() { 197 It("fails", func() { 198 data, err := ioutil.ReadFile("testdata/bad-label.tar.gz") 199 Expect(err).NotTo(HaveOccurred()) 200 201 _, err = ccpp.Parse(data) 202 Expect(err.Error()).To(ContainSubstring("invalid label 'Bad-Label!'. Label must be non-empty, can only consist of alphanumerics, symbols from '.+-_', and can only begin with alphanumerics")) 203 }) 204 }) 205 206 Context("when the tar file is corrupted", func() { 207 It("fails", func() { 208 data, err := ioutil.ReadFile("testdata/corrupted-package.tar.gz") 209 Expect(err).NotTo(HaveOccurred()) 210 211 _, err = ccpp.Parse(data) 212 Expect(err).To(MatchError("could not read Chaincode-Package-Metadata.json from tar: unexpected EOF")) 213 }) 214 }) 215 216 Context("when the tar has non-regular files", func() { 217 It("fails", func() { 218 data, err := ioutil.ReadFile("testdata/non-regular-file.tar.gz") 219 Expect(err).NotTo(HaveOccurred()) 220 221 _, err = ccpp.Parse(data) 222 Expect(err).To(MatchError("tar entry code.tar.gz is not a regular file, type 50")) 223 }) 224 }) 225 226 Context("when the tar has a corrupt header entry", func() { 227 It("fails", func() { 228 data, err := ioutil.ReadFile("testdata/corrupted-header.tar.gz") 229 Expect(err).NotTo(HaveOccurred()) 230 231 _, err = ccpp.Parse(data) 232 Expect(err).To(MatchError("error inspecting next tar header: flate: corrupt input before offset 86")) 233 }) 234 }) 235 236 Context("when the tar has too many entries", func() { 237 It("logs a warning but otherwise allows it", func() { 238 data, err := ioutil.ReadFile("testdata/too-many-files.tar.gz") 239 Expect(err).NotTo(HaveOccurred()) 240 241 _, err = ccpp.Parse(data) 242 Expect(err).NotTo(HaveOccurred()) 243 }) 244 }) 245 246 Context("when the tar is missing a code-package", func() { 247 It("fails", func() { 248 data, err := ioutil.ReadFile("testdata/missing-codepackage.tar.gz") 249 Expect(err).NotTo(HaveOccurred()) 250 251 _, err = ccpp.Parse(data) 252 Expect(err).To(MatchError("did not find a code package inside the package")) 253 }) 254 }) 255 }) 256 }) 257 258 var _ = Describe("ChaincodePackageLocator", func() { 259 var locator *persistence.ChaincodePackageLocator 260 261 BeforeEach(func() { 262 locator = &persistence.ChaincodePackageLocator{ 263 ChaincodeDir: "/fake-dir", 264 } 265 }) 266 267 Describe("ChaincodePackageStreamer", func() { 268 It("creates a ChaincodePackageStreamer for the given packageID", func() { 269 streamer := locator.ChaincodePackageStreamer("test-package") 270 Expect(streamer).To(Equal(&persistence.ChaincodePackageStreamer{ 271 PackagePath: "/fake-dir/test-package.tar.gz", 272 })) 273 }) 274 }) 275 }) 276 277 var _ = Describe("ChaincodePackageStreamer", func() { 278 var streamer *persistence.ChaincodePackageStreamer 279 280 BeforeEach(func() { 281 streamer = &persistence.ChaincodePackageStreamer{ 282 PackagePath: "testdata/good-package.tar.gz", 283 } 284 }) 285 286 Describe("Metadata", func() { 287 It("reads the metadata from the package", func() { 288 md, err := streamer.Metadata() 289 Expect(err).NotTo(HaveOccurred()) 290 Expect(md).To(Equal(&persistence.ChaincodePackageMetadata{ 291 Type: "Fake-Type", 292 Path: "Fake-Path", 293 Label: "Real-Label", 294 })) 295 }) 296 297 Context("when the metadata file cannot be found", func() { 298 BeforeEach(func() { 299 streamer.PackagePath = "testdata/missing-metadata.tar.gz" 300 }) 301 302 It("wraps and returns the error", func() { 303 _, err := streamer.Metadata() 304 Expect(err).To(MatchError("could not get metadata file: did not find file 'metadata.json' in package")) 305 }) 306 }) 307 308 Context("when the metadata file cannot be parsed", func() { 309 BeforeEach(func() { 310 streamer.PackagePath = "testdata/bad-metadata.tar.gz" 311 }) 312 313 It("wraps and returns the error", func() { 314 _, err := streamer.Metadata() 315 Expect(err).To(MatchError("could not parse metadata file: invalid character '\\n' in string literal")) 316 }) 317 }) 318 }) 319 320 Describe("Code", func() { 321 It("reads a file from the package", func() { 322 code, err := streamer.Code() 323 Expect(err).NotTo(HaveOccurred()) 324 codeBytes, err := ioutil.ReadAll(code) 325 code.Close() 326 Expect(err).NotTo(HaveOccurred()) 327 Expect(codeBytes).To(Equal([]byte("package"))) 328 }) 329 330 Context("when the file cannot be found because the code is not a regular file", func() { 331 BeforeEach(func() { 332 streamer.PackagePath = "testdata/missing-codepackage.tar.gz" 333 }) 334 335 It("wraps and returns the error", func() { 336 _, err := streamer.Code() 337 Expect(err).To(MatchError("could not get code package: did not find file 'code.tar.gz' in package")) 338 }) 339 }) 340 }) 341 342 Describe("File", func() { 343 It("reads a file from the package", func() { 344 code, err := streamer.File("code.tar.gz") 345 Expect(err).NotTo(HaveOccurred()) 346 codeBytes, err := ioutil.ReadAll(code) 347 code.Close() 348 Expect(err).NotTo(HaveOccurred()) 349 Expect(codeBytes).To(Equal([]byte("package"))) 350 }) 351 352 Context("when the file is not a regular file", func() { 353 BeforeEach(func() { 354 streamer.PackagePath = "testdata/non-regular-file.tar.gz" 355 }) 356 357 It("wraps and returns the error", func() { 358 _, err := streamer.File("code.tar.gz") 359 Expect(err).To(MatchError("tar entry code.tar.gz is not a regular file, type 50")) 360 }) 361 }) 362 363 Context("when the code cannot be found because the archive is corrupt", func() { 364 BeforeEach(func() { 365 streamer.PackagePath = "testdata/bad-archive.tar.gz" 366 }) 367 368 It("wraps and returns the error", func() { 369 _, err := streamer.File("code.tar.gz") 370 Expect(err).To(MatchError("could not open chaincode package at 'testdata/bad-archive.tar.gz': open testdata/bad-archive.tar.gz: no such file or directory")) 371 }) 372 }) 373 374 Context("when the code cannot be found because the header is corrupt", func() { 375 BeforeEach(func() { 376 streamer.PackagePath = "testdata/corrupted-header.tar.gz" 377 }) 378 379 It("wraps and returns the error", func() { 380 _, err := streamer.File("code.tar.gz") 381 Expect(err).To(MatchError("error inspecting next tar header: flate: corrupt input before offset 86")) 382 }) 383 }) 384 385 Context("when the code cannot be found because the gzip is corrupt", func() { 386 BeforeEach(func() { 387 streamer.PackagePath = "testdata/corrupted-gzip.tar.gz" 388 }) 389 390 It("wraps and returns the error", func() { 391 _, err := streamer.File("code.tar.gz") 392 Expect(err).To(MatchError("error reading as gzip stream: unexpected EOF")) 393 }) 394 }) 395 }) 396 })