Skip to content

Commit

Permalink
Merge branch 'main' into initialize-logging
Browse files Browse the repository at this point in the history
  • Loading branch information
Terry Howe authored Mar 13, 2023
2 parents 1627767 + 63d4e54 commit 309561f
Show file tree
Hide file tree
Showing 12 changed files with 580 additions and 39 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ require (
github.com/spf13/cobra v1.6.1
github.com/spf13/pflag v1.0.5
gopkg.in/yaml.v3 v3.0.1
oras.land/oras-go/v2 v2.0.0-20230224055117-216f081e33ba
oras.land/oras-go/v2 v2.0.1
)

require (
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
oras.land/oras-go/v2 v2.0.0-20230224055117-216f081e33ba h1:KTtDVzF+8+zXXOxm7JXMrkM6b222L4juxRFI+S3I+nY=
oras.land/oras-go/v2 v2.0.0-20230224055117-216f081e33ba/go.mod h1:PWnWc/Kyyg7wUTUsDHshrsJkzuxXzreeMd6NrfdnFSo=
oras.land/oras-go/v2 v2.0.1 h1:fdnzCXT6yBQziJNJrCqaUPd6Ww7j6M0qLrtFA80tTeM=
oras.land/oras-go/v2 v2.0.1/go.mod h1:PWnWc/Kyyg7wUTUsDHshrsJkzuxXzreeMd6NrfdnFSo=
16 changes: 9 additions & 7 deletions test/e2e/internal/testdata/multi_arch/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ import (
)

var (
Tag = "multi"
Digest = "sha256:e2bfc9cc6a84ec2d7365b5a28c6bc5806b7fa581c9ad7883be955a64e3cc034f"
Manifest = `{"mediaType":"application/vnd.oci.image.index.v1+json","schemaVersion":2,"manifests":[{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:9d84a5716c66a1d1b9c13f8ed157ba7d1edfe7f9b8766728b8a1f25c0d9c14c1","size":458,"platform":{"architecture":"amd64","os":"linux"}},{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:4f93460061882467e6fb3b772dc6ab72130d9ac1906aed2fc7589a5cd145433c","size":458,"platform":{"architecture":"arm64","os":"linux"}},{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:58efe73e78fe043ca31b89007a025c594ce12aa7e6da27d21c7b14b50112e255","size":458,"platform":{"architecture":"arm","os":"linux","variant":"v7"}}]}`
Descriptor = `{"mediaType":"application/vnd.oci.image.index.v1+json","digest":"sha256:e2bfc9cc6a84ec2d7365b5a28c6bc5806b7fa581c9ad7883be955a64e3cc034f","size":706}`
IndexReferrerDigest = "sha256:d3cf790759b006e1a2aeee52f9b1ee250bb848fce7e873b992b86bf9408f12d0"
IndexStateKeys = []match.StateKey{
Tag = "multi"
Digest = "sha256:e2bfc9cc6a84ec2d7365b5a28c6bc5806b7fa581c9ad7883be955a64e3cc034f"
Manifest = `{"mediaType":"application/vnd.oci.image.index.v1+json","schemaVersion":2,"manifests":[{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:9d84a5716c66a1d1b9c13f8ed157ba7d1edfe7f9b8766728b8a1f25c0d9c14c1","size":458,"platform":{"architecture":"amd64","os":"linux"}},{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:4f93460061882467e6fb3b772dc6ab72130d9ac1906aed2fc7589a5cd145433c","size":458,"platform":{"architecture":"arm64","os":"linux"}},{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:58efe73e78fe043ca31b89007a025c594ce12aa7e6da27d21c7b14b50112e255","size":458,"platform":{"architecture":"arm","os":"linux","variant":"v7"}}]}`
Descriptor = `{"mediaType":"application/vnd.oci.image.index.v1+json","digest":"sha256:e2bfc9cc6a84ec2d7365b5a28c6bc5806b7fa581c9ad7883be955a64e3cc034f","size":706}`
IndexReferrerDigest = "sha256:d3cf790759b006e1a2aeee52f9b1ee250bb848fce7e873b992b86bf9408f12d0"
IndexReferrerStateKey = match.StateKey{Digest: "d3cf790759b0", Name: "application/vnd.oci.image.manifest.v1+json"}
IndexReferrerConfigStateKey = match.StateKey{Digest: "44136fa355b3", Name: "referrer.index"}
IndexStateKeys = []match.StateKey{
{Digest: "2ef548696ac7", Name: "hello.tar"},
{Digest: "fe9dbc99451d", Name: "application/vnd.oci.image.config.v1+json"},
{Digest: "9d84a5716c66", Name: "application/vnd.oci.image.manifest.v1+json"},
Expand Down Expand Up @@ -59,7 +61,7 @@ var (
LayerName = "hello.tar"
LinuxAMD64ReferrerStateKey = match.StateKey{Digest: "57e6462826c8", Name: "application/vnd.oci.image.manifest.v1+json"}
LinuxAMD64ReferrerConfigStateKey = match.StateKey{Digest: "44136fa355b3", Name: "referrer.image"}
ImageStateKeys = []match.StateKey{
LinuxAMD64StateKeys = []match.StateKey{
{Digest: "9d84a5716c66", Name: ocispec.MediaTypeImageManifest},
{Digest: "fe9dbc99451d", Name: ocispec.MediaTypeImageConfig},
{Digest: "2ef548696ac7", Name: "hello.tar"},
Expand Down
6 changes: 6 additions & 0 deletions test/e2e/internal/utils/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ func (opts *ExecOption) MatchErrKeyWords(keywords ...string) *ExecOption {
return opts
}

// MatchRequestHeaders adds keywords matching to each sent request.
func (opts *ExecOption) MatchRequestHeaders(headers ...string) *ExecOption {
opts.stderr = append(opts.stderr, match.NewRequestHeaderMatcher(headers))
return opts
}

// MatchContent adds full content matching to the execution.
func (opts *ExecOption) MatchContent(content string) *ExecOption {
if opts.exitCode == 0 {
Expand Down
14 changes: 9 additions & 5 deletions test/e2e/internal/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ limitations under the License.

package utils

const (
LayoutFlag = "--oci-layout"
FromLayout = "--from-oci-layout"
ToLayout = "--to-oci-layout"
)
var Flags = struct {
Layout string
FromLayout string
ToLayout string
}{
"--oci-layout",
"--from-oci-layout",
"--to-oci-layout",
}
4 changes: 2 additions & 2 deletions test/e2e/internal/utils/match/keywords.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import (
)

// keywordMatcher provides selective matching of the output.
// The match will pass if all key words existed case-insensitively in the
// output.
// The match will pass if all the keywords exist case-insensitively
// in the output.
type keywordMatcher []string

func NewKeywordMatcher(kw []string) keywordMatcher {
Expand Down
82 changes: 82 additions & 0 deletions test/e2e/internal/utils/match/request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
Copyright The ORAS Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package match

import (
"fmt"
"strings"

. "github.com/onsi/gomega"
"github.com/onsi/gomega/gbytes"
)

// requestHeaderMatcher provides matching for request content.
// It looks into the debug output of an operation and the match will pass
// if all the headers exist in every sent request.
type requestHeaderMatcher []string

// NewRequestHeaderMatcher returns a request header matcher.
func NewRequestHeaderMatcher(kw []string) requestHeaderMatcher {
return requestHeaderMatcher(kw)
}

// Match matches got with wanted headers.
func (r requestHeaderMatcher) Match(got *gbytes.Buffer) {
var missed []string

raw := string(got.Contents())
reqs := getRequestHeaders(getRequests(raw))
for _, req := range reqs {
for _, w := range r {
if !strings.Contains(req, w) {
missed = append(missed, w)
}
}
}

if len(missed) != 0 {
fmt.Printf("Headers missed: %v\n", missed)
panic("failed to match all headers")
}
}

// getRequests parses raw debug output to a string slice
// containing each request.
func getRequests(debugOutput string) []string {
reqs := strings.Split(debugOutput, "> Request URL:")
Expect(len(reqs) > 0).To(BeTrue(), "should output requests in debug logs")
reqs = reqs[1:]
// trim the response content
for i, req := range reqs {
req = strings.Split(req, "< Response Status:")[0]
reqs[i] = req
}
return reqs
}

// getRequestHeaders takes a string slice containing requests
// and extract request headers from them.
func getRequestHeaders(reqs []string) []string {
headers := make([]string, len(reqs))
for i, req := range reqs {
// extract the header content from each request
_, header, ok := strings.Cut(req, "> Request headers:\n")
if ok {
headers[i] = header
}
}
return headers
}
24 changes: 12 additions & 12 deletions test/e2e/suite/command/blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,15 +250,15 @@ var _ = Describe("Common registry users:", func() {
var _ = Describe("OCI image layout users:", func() {
prepare := func(from string) string {
tmpRoot := GinkgoT().TempDir()
ORAS("cp", from, ToLayout, tmpRoot).WithDescription("prepare image from registry to OCI layout").Exec()
ORAS("cp", from, Flags.ToLayout, tmpRoot).WithDescription("prepare image from registry to OCI layout").Exec()
return tmpRoot
}
When("running `blob delete`", func() {
It("should not support deleting a blob", func() {
toDeleteRef := LayoutRef(prepare(RegistryRef(Host, ImageRepo, foobar.Tag)), foobar.FooBlobDigest)
ORAS("blob", "delete", LayoutFlag, toDeleteRef).
ORAS("blob", "delete", Flags.Layout, toDeleteRef).
WithInput(strings.NewReader("y")).
MatchErrKeyWords("Error:", "unknown flag", LayoutFlag).
MatchErrKeyWords("Error:", "unknown flag", Flags.Layout).
ExpectFailure().
Exec()
})
Expand All @@ -267,27 +267,27 @@ var _ = Describe("OCI image layout users:", func() {
When("running `blob fetch`", func() {
It("should fetch blob descriptor", func() {
root := prepare(RegistryRef(Host, ImageRepo, foobar.Tag))
ORAS("blob", "fetch", LayoutFlag, LayoutRef(root, foobar.FooBlobDigest), "--descriptor").
ORAS("blob", "fetch", Flags.Layout, LayoutRef(root, foobar.FooBlobDigest), "--descriptor").
MatchContent(foobar.FooBlobDescriptor).Exec()
})
It("should fetch blob content and output to stdout", func() {
root := prepare(RegistryRef(Host, ImageRepo, foobar.Tag))
ORAS("blob", "fetch", LayoutFlag, LayoutRef(root, foobar.FooBlobDigest), "--output", "-").
ORAS("blob", "fetch", Flags.Layout, LayoutRef(root, foobar.FooBlobDigest), "--output", "-").
MatchContent(foobar.FooBlobContent).Exec()
})
It("should fetch blob content and output to a file", func() {
root := prepare(RegistryRef(Host, ImageRepo, foobar.Tag))
tempDir := GinkgoT().TempDir()
contentPath := filepath.Join(tempDir, "fetched")
ORAS("blob", "fetch", LayoutFlag, LayoutRef(root, foobar.FooBlobDigest), "--output", contentPath).
ORAS("blob", "fetch", Flags.Layout, LayoutRef(root, foobar.FooBlobDigest), "--output", contentPath).
WithWorkDir(tempDir).Exec()
MatchFile(contentPath, foobar.FooBlobContent, DefaultTimeout)
})
It("should fetch blob descriptor and output content to a file", func() {
root := prepare(RegistryRef(Host, ImageRepo, foobar.Tag))
tempDir := GinkgoT().TempDir()
contentPath := filepath.Join(tempDir, "fetched")
ORAS("blob", "fetch", LayoutFlag, LayoutRef(root, foobar.FooBlobDigest), "--output", contentPath, "--descriptor").
ORAS("blob", "fetch", Flags.Layout, LayoutRef(root, foobar.FooBlobDigest), "--output", contentPath, "--descriptor").
MatchContent(foobar.FooBlobDescriptor).
WithWorkDir(tempDir).Exec()
MatchFile(contentPath, foobar.FooBlobContent, DefaultTimeout)
Expand All @@ -301,25 +301,25 @@ var _ = Describe("OCI image layout users:", func() {
mediaType := "test.media"
blobPath := WriteTempFile("blob", pushContent)
// test
ORAS("blob", "push", LayoutFlag, LayoutRef(tmpRoot, pushDigest), blobPath, "--media-type", mediaType, "--descriptor").
ORAS("blob", "push", Flags.Layout, LayoutRef(tmpRoot, pushDigest), blobPath, "--media-type", mediaType, "--descriptor").
MatchContent(fmt.Sprintf(pushDescFmt, mediaType)).Exec()
ORAS("blob", "push", LayoutFlag, LayoutRef(tmpRoot, pushDigest), blobPath, "-v").
ORAS("blob", "push", Flags.Layout, LayoutRef(tmpRoot, pushDigest), blobPath, "-v").
WithDescription("skip pushing if the blob already exists in the target repo").
MatchKeyWords("Exists").Exec()
// validate
ORAS("blob", "fetch", LayoutRef(tmpRoot, pushDigest), LayoutFlag, "--output", "-").MatchContent(pushContent).Exec()
ORAS("blob", "fetch", LayoutRef(tmpRoot, pushDigest), Flags.Layout, "--output", "-").MatchContent(pushContent).Exec()
})

It("should push a blob from a stdin and output the descriptor with specific media-type", func() {
// prepare
tmpRoot := GinkgoT().TempDir()
// test
mediaType := "test.media"
ORAS("blob", "push", LayoutFlag, LayoutRef(tmpRoot, pushDigest), "-", "--media-type", mediaType, "--descriptor", "--size", strconv.Itoa(len(pushContent))).
ORAS("blob", "push", Flags.Layout, LayoutRef(tmpRoot, pushDigest), "-", "--media-type", mediaType, "--descriptor", "--size", strconv.Itoa(len(pushContent))).
WithInput(strings.NewReader(pushContent)).
MatchContent(fmt.Sprintf(pushDescFmt, mediaType)).Exec()
// validate
ORAS("blob", "fetch", LayoutRef(tmpRoot, pushDigest), LayoutFlag, "--output", "-").MatchContent(pushContent).Exec()
ORAS("blob", "fetch", LayoutRef(tmpRoot, pushDigest), Flags.Layout, "--output", "-").MatchContent(pushContent).Exec()
})
})
})
Loading

0 comments on commit 309561f

Please sign in to comment.