Skip to content

Commit

Permalink
test: add E2E specs for oras blob push (oras-project#706)
Browse files Browse the repository at this point in the history
Resolves oras-project#587

Signed-off-by: Billy Zha <jinzha1@microsoft.com>
  • Loading branch information
qweeah authored and TerryHowe committed Feb 2, 2023
1 parent dfc859b commit e787b1c
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 25 deletions.
10 changes: 10 additions & 0 deletions test/e2e/internal/utils/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"regexp"
"time"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gbytes"
)
Expand Down Expand Up @@ -63,6 +64,15 @@ func MatchFile(filepath string, want string, timeout time.Duration) {
Eventually(gbytes.BufferReader(f)).WithTimeout(timeout).Should(gbytes.Say(want))
}

// WriteTempFile writes content into name under a temp folder.
func WriteTempFile(name string, content string) (path string) {
tempDir := GinkgoT().TempDir()
path = filepath.Join(tempDir, name)
err := os.WriteFile(path, []byte(content), 0666)
Expect(err).ToNot(HaveOccurred())
return path
}

func copyFile(srcFile, dstFile string) error {
to, err := os.Create(dstFile)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions test/e2e/suite/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ var _ = Describe("Common registry user", Ordered, func() {
RunWithoutLogin("push", "-a", "key=value", Host+"/repo:tag")
RunWithoutLogin("pull", Host+"/repo:tag")
RunWithoutLogin("manifest", "fetch", Host+"/repo:tag")
RunWithoutLogin("blob", "push", Host+"/repo", WriteTempFile("blob", "test"))
RunWithoutLogin("tag", Host+"/repo:tag", "tag1")
RunWithoutLogin("repo", "ls", Host)
RunWithoutLogin("repo", "tags", Reference(Host, "repo", ""))
Expand Down
108 changes: 92 additions & 16 deletions test/e2e/suite/command/blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,80 @@ limitations under the License.
package command

import (
"os"
"fmt"
"path/filepath"
"strconv"
"strings"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gbytes"
. "oras.land/oras/test/e2e/internal/utils"
)

const (
pushContent = "test-blob"
pushDigest = "sha256:e1ca41574914ba00e8ed5c8fc78ec8efdfd48941c7e48ad74dad8ada7f2066d8"
wrongDigest = "sha256:e1ca41574914ba00e8ed5c8fc78ec8efdfd48941c7e48ad74dad8ada7f2066d9"
pushDescFmt = `{"mediaType":"%s","digest":"sha256:e1ca41574914ba00e8ed5c8fc78ec8efdfd48941c7e48ad74dad8ada7f2066d8","size":9}`
)

var _ = Describe("ORAS beginners:", func() {
repoFmt := fmt.Sprintf("command/blob/push/%d/%%s", GinkgoRandomSeed())
When("running blob command", func() {
runAndShowPreviewInHelp([]string{"blob"})
RunAndShowPreviewInHelp([]string{"blob"})

When("running `blob push`", func() {
RunAndShowPreviewInHelp([]string{"blob", "push"}, preview_desc, example_desc)
It("should fail to read blob content and password from stdin at the same time", func() {
repo := fmt.Sprintf(repoFmt, "password-stdin")
ORAS("blob", "push", Reference(Host, repo, ""), "--password-stdin", "-").
WithFailureCheck().
MatchTrimmedContent("Error: `-` read file from input and `--password-stdin` read password from input cannot be both used").Exec()
})
It("should fail to push a blob from stdin but no blob size provided", func() {
repo := fmt.Sprintf(repoFmt, "no-size")
ORAS("blob", "push", Reference(Host, repo, pushDigest), "-").
WithInput(strings.NewReader(pushContent)).
WithFailureCheck().
MatchTrimmedContent("Error: `--size` must be provided if the blob is read from stdin").Exec()
})

It("should fail to push a blob from stdin if invalid blob size provided", func() {
repo := fmt.Sprintf(repoFmt, "invalid-stdin-size")
ORAS("blob", "push", Reference(Host, repo, pushDigest), "-", "--size", "3").
WithInput(strings.NewReader(pushContent)).WithFailureCheck().
Exec()
})

It("should fail to push a blob from stdin if invalid digest provided", func() {
repo := fmt.Sprintf(repoFmt, "invalid-stdin-digest")
ORAS("blob", "push", Reference(Host, repo, wrongDigest), "-", "--size", strconv.Itoa(len(pushContent))).
WithInput(strings.NewReader(pushContent)).WithFailureCheck().
Exec()
})

It("should fail to push a blob from file if invalid blob size provided", func() {
repo := fmt.Sprintf(repoFmt, "invalid-file-digest")
blobPath := WriteTempFile("blob", pushContent)
ORAS("blob", "push", Reference(Host, repo, pushDigest), blobPath, "--size", "3").
WithFailureCheck().
Exec()
})

It("should fail to push a blob from file if invalid digest provided", func() {
repo := fmt.Sprintf(repoFmt, "invalid-stdin-size")
blobPath := WriteTempFile("blob", pushContent)
ORAS("blob", "push", Reference(Host, repo, wrongDigest), blobPath, "--size", strconv.Itoa(len(pushContent))).
WithInput(strings.NewReader(pushContent)).WithFailureCheck().
Exec()
})

It("should fail if no reference is provided", func() {
ORAS("blob", "push").WithFailureCheck().Exec()
})
})

When("running `blob fetch`", func() {
runAndShowPreviewInHelp([]string{"blob", "fetch"}, preview_desc, example_desc)
RunAndShowPreviewInHelp([]string{"blob", "fetch"}, preview_desc, example_desc)

It("should call sub-commands with aliases", func() {
ORAS("blob", "get", "--help").
Expand Down Expand Up @@ -69,10 +128,35 @@ var _ = Describe("ORAS beginners:", func() {
})

var _ = Describe("Common registry users:", func() {
repoFmt := fmt.Sprintf("command/blob/push/%d/%%s", GinkgoRandomSeed())
When("running `blob push`", func() {
It("should push a blob from a file and output the descriptor with specific media-type", func() {
mediaType := "test.media"
repo := fmt.Sprintf(repoFmt, "blob-file-media-type")
blobPath := WriteTempFile("blob", pushContent)
ORAS("blob", "push", Reference(Host, repo, ""), blobPath, "--media-type", mediaType, "--descriptor").
MatchContent(fmt.Sprintf(pushDescFmt, mediaType)).Exec()
ORAS("blob", "fetch", Reference(Host, repo, pushDigest), "--output", "-").MatchContent(pushContent).Exec()

ORAS("blob", "push", Reference(Host, repo, ""), blobPath, "-v").
WithDescription("skip the pushing if the blob already exists in the target repo").
MatchKeyWords("Exists").Exec()

})

It("should push a blob from a stdin and output the descriptor with specific media-type", func() {
mediaType := "test.media"
repo := fmt.Sprintf(repoFmt, "blob-file-media-type")
ORAS("blob", "push", Reference(Host, repo, pushDigest), "-", "--media-type", mediaType, "--descriptor", "--size", strconv.Itoa(len(pushContent))).
WithInput(strings.NewReader(pushContent)).
MatchContent(fmt.Sprintf(pushDescFmt, mediaType)).Exec()
ORAS("blob", "fetch", Reference(Host, repo, pushDigest), "--output", "-").MatchContent(pushContent).Exec()
})
})

var blobDigest = "sha256:2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"
var blobContent = "foo"
var blobDescriptor = `{"mediaType":"application/octet-stream","digest":"sha256:2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae","size":3}`

When("running `blob fetch`", func() {
It("should fetch blob descriptor ", func() {
ORAS("blob", "fetch", Reference(Host, repo, blobDigest), "--descriptor").
Expand All @@ -87,23 +171,15 @@ var _ = Describe("Common registry users:", func() {
contentPath := filepath.Join(tempDir, "fetched")
ORAS("blob", "fetch", Reference(Host, repo, blobDigest), "--output", contentPath).
WithWorkDir(tempDir).Exec()
Expect(contentPath).Should(BeAnExistingFile())
f, err := os.Open(contentPath)
Expect(err).ShouldNot(HaveOccurred())
defer f.Close()
Eventually(gbytes.BufferReader(f)).Should(gbytes.Say(blobContent))
MatchFile(contentPath, blobContent, DefaultTimeout)
})
It("should fetch blob descriptor and output content to a file", func() {
tempDir := GinkgoT().TempDir()
contentPath := filepath.Join(tempDir, "fetched")
ORAS("blob", "fetch", Reference(Host, repo, blobDigest), "--output", contentPath, "--descriptor").
MatchContent(blobDescriptor).
WithWorkDir(tempDir).Exec()
Expect(contentPath).Should(BeAnExistingFile())
f, err := os.Open(contentPath)
Expect(err).ShouldNot(HaveOccurred())
defer f.Close()
Eventually(gbytes.BufferReader(f)).Should(gbytes.Say(blobContent))
MatchFile(contentPath, blobContent, DefaultTimeout)
})
})
})
6 changes: 3 additions & 3 deletions test/e2e/suite/command/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ const (

var _ = Describe("ORAS beginners:", func() {
When("running manifest command", func() {
runAndShowPreviewInHelp([]string{"manifest"})
runAndShowPreviewInHelp([]string{"manifest", "fetch"}, preview_desc, example_desc)
RunAndShowPreviewInHelp([]string{"manifest"})
RunAndShowPreviewInHelp([]string{"manifest", "fetch"}, preview_desc, example_desc)

It("should call sub-commands with aliases", func() {
ORAS("manifest", "get", "--help").
Expand Down Expand Up @@ -80,7 +80,7 @@ var _ = Describe("ORAS beginners:", func() {
})
})

func runAndShowPreviewInHelp(args []string, keywords ...string) {
func RunAndShowPreviewInHelp(args []string, keywords ...string) {
It(fmt.Sprintf("should run %q command", strings.Join(args, " ")), func() {
ORAS(append(args, "--help")...).
MatchKeyWords(append(keywords, "[Preview] "+args[len(args)-1], "\nUsage:")...).
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/suite/command/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (

var _ = Describe("ORAS beginners:", func() {
When("running repo command", func() {
runAndShowPreviewInHelp([]string{"repo"})
RunAndShowPreviewInHelp([]string{"repo"})
When("running `repo ls`", func() {
It("should show preview in help", func() {
ORAS("repo", "ls", "--help").MatchKeyWords("[Preview] List", preview_desc, example_desc).Exec()
Expand Down
6 changes: 1 addition & 5 deletions test/e2e/suite/command/tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,13 @@ limitations under the License.
package command

import (
"fmt"

. "github.com/onsi/ginkgo/v2"
. "oras.land/oras/test/e2e/internal/utils"
)

var repoFmt = fmt.Sprintf("command/tag/%%s/%d/%%s", GinkgoRandomSeed())

var _ = Describe("ORAS beginners:", func() {
When("running repo command", func() {
runAndShowPreviewInHelp([]string{"tag"})
RunAndShowPreviewInHelp([]string{"tag"})
It("should fail when no manifest reference provided", func() {
ORAS("tag").WithFailureCheck().MatchErrKeyWords("Error:").Exec()
})
Expand Down

0 comments on commit e787b1c

Please sign in to comment.