Skip to content

Commit

Permalink
adding CacheExtension method for caching MetadataDependency in extens…
Browse files Browse the repository at this point in the history
…ion with tests
  • Loading branch information
pacostas committed Jun 6, 2023
1 parent 56915c2 commit 3278986
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 0 deletions.
62 changes: 62 additions & 0 deletions internal/dependency_cacher.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,65 @@ func (dc DependencyCacher) Cache(root string, deps []cargo.ConfigMetadataDepende

return dependencies, nil
}

func (dc DependencyCacher) CacheExtension(root string, deps []cargo.ConfigExtensionMetadataDependency) ([]cargo.ConfigExtensionMetadataDependency, error) {
dc.logger.Process("Downloading dependencies...")
dir := filepath.Join(root, "dependencies")
err := os.MkdirAll(dir, os.ModePerm)
if err != nil {
return nil, fmt.Errorf("failed to create dependencies directory: %s", err)
}

var dependencies []cargo.ConfigExtensionMetadataDependency
for _, dep := range deps {
dc.logger.Subprocess("%s (%s) [%s]", dep.ID, dep.Version, strings.Join(dep.Stacks, ", "))

source, err := dc.downloader.Drop("", dep.URI)
if err != nil {
return nil, fmt.Errorf("failed to download dependency: %s", err)
}

checksum := dep.Checksum
_, hash, _ := strings.Cut(dep.Checksum, ":")

if checksum == "" {
checksum = fmt.Sprintf("sha256:%s", dep.SHA256)
hash = dep.SHA256
}

if checksum == "sha256:" {
return nil, fmt.Errorf("failed to create file for %s: no sha256 or checksum provided", dep.ID)
}

dc.logger.Action("↳ dependencies/%s", hash)

validatedSource := cargo.NewValidatedReader(source, checksum)

destination, err := os.Create(filepath.Join(dir, hash))
if err != nil {
return nil, fmt.Errorf("failed to create destination file: %s", err)
}

_, err = io.Copy(destination, validatedSource)
if err != nil {
return nil, fmt.Errorf("failed to copy dependency: %s", err)
}

err = destination.Close()
if err != nil {
return nil, fmt.Errorf("failed to close dependency destination: %s", err)
}

err = source.Close()
if err != nil {
return nil, fmt.Errorf("failed to close dependency source: %s", err)
}

dep.URI = fmt.Sprintf("file:///dependencies/%s", hash)
dependencies = append(dependencies, dep)
}

dc.logger.Break()

return dependencies, nil
}
110 changes: 110 additions & 0 deletions internal/dependency_cacher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,59 @@ func testDependencyCacher(t *testing.T, context spec.G, it spec.S) {

})

it("caches extension dependencies and returns updated dependencies list", func() {
deps, err := cacher.CacheExtension(tmpDir, []cargo.ConfigExtensionMetadataDependency{
{
ID: "dep-1",
Version: "1.2.3",
Stacks: []string{"some-stack"},
URI: "http://dep1-uri",
SHA256: "3c9de6683673f3e8039599d5200d533807c6c35fd9e35d6b6d77009122868f0f",
},
{
ID: "dep-2",
Version: "4.5.6",
Stacks: []string{"some-stack", "some-other-stack"},
URI: "http://dep2-uri",
Checksum: "sha256:bfc72d62682f4a2edc3218d70b1f7052e4f336c179a8f19ef12ee721d4ea29b7",
},
})
Expect(err).NotTo(HaveOccurred())
Expect(deps).To(Equal([]cargo.ConfigExtensionMetadataDependency{
{
ID: "dep-1",
Version: "1.2.3",
Stacks: []string{"some-stack"},
URI: "file:///dependencies/3c9de6683673f3e8039599d5200d533807c6c35fd9e35d6b6d77009122868f0f",
SHA256: "3c9de6683673f3e8039599d5200d533807c6c35fd9e35d6b6d77009122868f0f",
},
{
ID: "dep-2",
Version: "4.5.6",
Stacks: []string{"some-stack", "some-other-stack"},
URI: "file:///dependencies/bfc72d62682f4a2edc3218d70b1f7052e4f336c179a8f19ef12ee721d4ea29b7",
Checksum: "sha256:bfc72d62682f4a2edc3218d70b1f7052e4f336c179a8f19ef12ee721d4ea29b7",
},
}))

Expect(downloader.DropCall.Receives.Root).To(Equal(""))

contents, err := os.ReadFile(filepath.Join(tmpDir, "dependencies", "3c9de6683673f3e8039599d5200d533807c6c35fd9e35d6b6d77009122868f0f"))
Expect(err).NotTo(HaveOccurred())
Expect(string(contents)).To(Equal("dep1-contents"))

contents, err = os.ReadFile(filepath.Join(tmpDir, "dependencies", "bfc72d62682f4a2edc3218d70b1f7052e4f336c179a8f19ef12ee721d4ea29b7"))
Expect(err).NotTo(HaveOccurred())
Expect(string(contents)).To(Equal("dep2-contents"))

Expect(output.String()).To(ContainSubstring(" Downloading dependencies..."))
Expect(output.String()).To(ContainSubstring(" dep-1 (1.2.3) [some-stack]"))
Expect(output.String()).To(ContainSubstring(" ↳ dependencies/3c9de6683673f3e8039599d5200d533807c6c35fd9e35d6b6d77009122868f0f"))
Expect(output.String()).To(ContainSubstring(" dep-2 (4.5.6) [some-stack, some-other-stack]"))
Expect(output.String()).To(ContainSubstring(" ↳ dependencies/bfc72d62682f4a2edc3218d70b1f7052e4f336c179a8f19ef12ee721d4ea29b7"))

})

context("failure cases", func() {
context("when the dependencies directory cannot be created", func() {
it.Before(func() {
Expand All @@ -127,6 +180,12 @@ func testDependencyCacher(t *testing.T, context spec.G, it spec.S) {
Expect(err).To(MatchError(ContainSubstring("failed to create dependencies directory:")))
Expect(err).To(MatchError(ContainSubstring("permission denied")))
})

it("CacheExtension returns an error", func() {
_, err := cacher.CacheExtension(tmpDir, nil)
Expect(err).To(MatchError(ContainSubstring("failed to create dependencies directory:")))
Expect(err).To(MatchError(ContainSubstring("permission denied")))
})
})

context("when a dependency cannot be downloaded", func() {
Expand All @@ -138,6 +197,15 @@ func testDependencyCacher(t *testing.T, context spec.G, it spec.S) {
})
Expect(err).To(MatchError("failed to download dependency: no such dependency: http://unknown-dep"))
})

it("CacheExtension returns an error", func() {
_, err := cacher.CacheExtension(tmpDir, []cargo.ConfigExtensionMetadataDependency{
{
URI: "http://unknown-dep",
},
})
Expect(err).To(MatchError("failed to download dependency: no such dependency: http://unknown-dep"))
})
})

context("when the destination file cannot be created", func() {
Expand All @@ -159,6 +227,17 @@ func testDependencyCacher(t *testing.T, context spec.G, it spec.S) {
Expect(err).To(MatchError(ContainSubstring("failed to create destination file:")))
Expect(err).To(MatchError(ContainSubstring("permission denied")))
})

it("CacheExtension returns an error", func() {
_, err := cacher.CacheExtension(tmpDir, []cargo.ConfigExtensionMetadataDependency{
{
URI: "http://dep1-uri",
SHA256: "3c9de6683673f3e8039599d5200d533807c6c35fd9e35d6b6d77009122868f0f",
},
})
Expect(err).To(MatchError(ContainSubstring("failed to create destination file:")))
Expect(err).To(MatchError(ContainSubstring("permission denied")))
})
})

context("when we fail to read the downloaded file", func() {
Expand All @@ -171,6 +250,16 @@ func testDependencyCacher(t *testing.T, context spec.G, it spec.S) {
})
Expect(err).To(MatchError("failed to copy dependency: failed to read"))
})

it("CacheExtension returns an error", func() {
_, err := cacher.CacheExtension(tmpDir, []cargo.ConfigExtensionMetadataDependency{
{
URI: "http://error-dep",
SHA256: "some-sha",
},
})
Expect(err).To(MatchError("failed to copy dependency: failed to read"))
})
})

context("when the dependency has neither a SHA256 nor a checksum", func() {
Expand All @@ -183,6 +272,17 @@ func testDependencyCacher(t *testing.T, context spec.G, it spec.S) {
})
Expect(err).To(MatchError("failed to create file for no-checksum-dep: no sha256 or checksum provided"))
})

it("CacheExtension returns a clear error", func() {
_, err := cacher.CacheExtension(tmpDir, []cargo.ConfigExtensionMetadataDependency{
{
URI: "http://error-dep",
ID: "no-checksum-dep",
},
})
Expect(err).To(MatchError("failed to create file for no-checksum-dep: no sha256 or checksum provided"))
})

})

context("when the checksum does not match", func() {
Expand All @@ -195,6 +295,16 @@ func testDependencyCacher(t *testing.T, context spec.G, it spec.S) {
})
Expect(err).To(MatchError("failed to copy dependency: validation error: checksum does not match"))
})

it("CacheExtension returns an error", func() {
_, err := cacher.CacheExtension(tmpDir, []cargo.ConfigExtensionMetadataDependency{
{
URI: "http://dep1-uri",
SHA256: "invalid-sha",
},
})
Expect(err).To(MatchError("failed to copy dependency: validation error: checksum does not match"))
})
})
})
})
Expand Down

0 comments on commit 3278986

Please sign in to comment.