Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(e2e): add e2e specs for oras attach #805

Merged
merged 56 commits into from
Feb 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
d17b0a4
add test and fix license
qweeah Jan 16, 2023
f4e7398
Remove focused
qweeah Jan 16, 2023
ee2436d
add fallback
qweeah Jan 16, 2023
8222fd0
code clean
qweeah Jan 18, 2023
f03a6aa
add mount data for fallback testing
qweeah Jan 18, 2023
db50edc
fix: deduplicate copy status logs
qweeah Jan 18, 2023
07eba1b
Merge branch 'fix-copy' into e2e-copy
qweeah Jan 18, 2023
e4b5dee
fix copying
qweeah Jan 18, 2023
6a5084b
fix post copy
qweeah Jan 18, 2023
b00dc9a
Merge branch 'fix-copy' into e2e-copy
qweeah Jan 18, 2023
bbe6b0c
bump e2e oras-go
qweeah Jan 18, 2023
f52682c
deduplicate based on digest
qweeah Jan 18, 2023
66eb21e
Merge branch 'fix-copy' into e2e-copy
qweeah Jan 18, 2023
41b7371
revert copy change
qweeah Jan 18, 2023
ae063cb
add test
qweeah Jan 18, 2023
f0aa94b
Merge remote-tracking branch 'origin_src/main' into e2e-copy
qweeah Jan 18, 2023
be1ffd9
fix e2e
qweeah Jan 18, 2023
a264e84
use billy's fork for testing
qweeah Jan 18, 2023
5aac978
correct version
qweeah Jan 18, 2023
cabd2b6
Merge remote-tracking branch 'origin_src/main' into e2e-copy
qweeah Jan 29, 2023
b5429cc
add test data for fallback registry
qweeah Jan 29, 2023
c962337
add test scripts for e2e
qweeah Feb 9, 2023
e90901b
Merge remote-tracking branch 'origin_src/main' into e2e-copy
qweeah Feb 9, 2023
bffc5b9
add logs
qweeah Feb 9, 2023
bbbf9a6
correct git action variables
qweeah Feb 9, 2023
4c6ad45
add action logs
qweeah Feb 9, 2023
755a436
rewrite host names
qweeah Feb 9, 2023
e1dec73
use shell script to run tests
qweeah Feb 9, 2023
ceb86de
fix typo
qweeah Feb 9, 2023
94f029f
correct ci path
qweeah Feb 9, 2023
543657d
resolve script errors
qweeah Feb 9, 2023
eadc5f6
correct test scripts
qweeah Feb 9, 2023
615bae1
update scripts
qweeah Feb 9, 2023
e8a920d
add sh
qweeah Feb 9, 2023
767a036
add license checker
qweeah Feb 9, 2023
88ce722
add cleanup
qweeah Feb 9, 2023
5590b9c
add docs
qweeah Feb 9, 2023
dcf3101
more docs
qweeah Feb 9, 2023
d625470
code clean
qweeah Feb 9, 2023
c919057
add execute permission to scripts
qweeah Feb 9, 2023
a0e2c18
rename script
qweeah Feb 9, 2023
bad0fc9
add container stopping logs
qweeah Feb 10, 2023
78d4c37
doc clean
qweeah Feb 10, 2023
58f7144
use pushd instead
qweeah Feb 10, 2023
1d1786a
run distribution as current user
qweeah Feb 10, 2023
2d7aff7
add exiting trap
qweeah Feb 10, 2023
8276913
add fallback registry to registry
qweeah Feb 10, 2023
ef06747
doc update
qweeah Feb 10, 2023
ca1b183
fix error in doc
qweeah Feb 12, 2023
a20d0c8
Merge remote-tracking branch 'origin_src/main' into e2e-copy
qweeah Feb 13, 2023
a62f7ee
fix typo
qweeah Feb 13, 2023
65004e6
test(e2e): add e2e specs for `oras attach`
qweeah Feb 13, 2023
1998210
code clean
qweeah Feb 13, 2023
d38af2b
Merge remote-tracking branch 'origin_src/main' into e2e-attach
qweeah Feb 15, 2023
b963f2b
Merge remote-tracking branch 'origin_src/main' into e2e-attach
qweeah Feb 16, 2023
32d091d
Merge remote-tracking branch 'origin_src/main' into e2e-attach
qweeah Feb 16, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,30 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package scenario
package foobar

import "oras.land/oras/test/e2e/internal/utils/match"

var (
blobFileNames = []string{
BlobFileNames = []string{
"foobar/foo1",
"foobar/foo2",
"foobar/bar",
}
pushFileStateKeys = []match.StateKey{
{Digest: "2c26b46b68ff", Name: blobFileNames[0]},
{Digest: "2c26b46b68ff", Name: blobFileNames[1]},
{Digest: "fcde2b2edba5", Name: blobFileNames[2]},
PushFileStateKeys = []match.StateKey{
{Digest: "2c26b46b68ff", Name: BlobFileNames[0]},
{Digest: "2c26b46b68ff", Name: BlobFileNames[1]},
{Digest: "fcde2b2edba5", Name: BlobFileNames[2]},
}

configFileName = "foobar/config.json"
configFileStateKey = match.StateKey{
ConfigFileName = "foobar/config.json"
ConfigFileStateKey = match.StateKey{
Digest: "46b68ac1696c", Name: "application/vnd.unknown.config.v1+json",
}

attachFileName = "foobar/to-be-attached"
attachFileMedia = "test/oras.e2e"
attachFileStateKey = match.StateKey{
Digest: "d3b29f7d12d9", Name: attachFileName,
AttachFileName = "foobar/to-be-attached"
AttachFileMedia = "test/oras.e2e"
AttachFileStateKey = match.StateKey{
Digest: "d3b29f7d12d9", Name: AttachFileName,
}
)
9 changes: 8 additions & 1 deletion test/e2e/internal/utils/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,14 @@ import (

var testFileRoot string

// CopyTestData copies test data into the temp test folder.
// CopyTestDataToTemp copies test data into a temp folder and return it.
func CopyTestDataToTemp() string {
tempDir := GinkgoT().TempDir()
Expect(CopyTestData(tempDir)).ShouldNot(HaveOccurred())
return tempDir
}

// CopyTestData copies test data into dstRoot.
func CopyTestData(dstRoot string) error {
return filepath.WalkDir(testFileRoot, func(path string, d fs.DirEntry, err error) error {
if err != nil {
Expand Down
178 changes: 178 additions & 0 deletions test/e2e/suite/command/attach.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/*
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 command

import (
"encoding/json"
"fmt"
"path/filepath"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"oras.land/oras/test/e2e/internal/testdata/foobar"
. "oras.land/oras/test/e2e/internal/utils"
"oras.land/oras/test/e2e/internal/utils/match"
)

func attachTestRepo(text string) string {
return fmt.Sprintf("command/attach/%d/%s", GinkgoRandomSeed(), text)
}

var _ = Describe("ORAS beginners:", func() {
When("running attach command", func() {
RunAndShowPreviewInHelp([]string{"attach"})

It("should show preview and help doc", func() {
ORAS("attach", "--help").MatchKeyWords("[Preview] Attach", PreviewDesc, ExampleDesc).Exec()
})

It("should fail when no subject reference provided", func() {
ORAS("attach", "--artifact-type", "oras.test").ExpectFailure().MatchErrKeyWords("Error:").Exec()
})

It("should fail if no file reference or manifest annotation provided", func() {
ORAS("attach", "--artifact-type", "oras.test", Reference(Host, ImageRepo, FoobarImageTag)).
ExpectFailure().MatchErrKeyWords("Error: no blob or manifest annotation are provided").Exec()
})
})
})

var _ = Describe("Common registry users:", func() {
When("running attach command", func() {
It("should attach a file to a subject", func() {
testRepo := attachTestRepo("simple")
tempDir := CopyTestDataToTemp()
subjectRef := Reference(Host, testRepo, FoobarImageTag)
prepare(Reference(Host, ImageRepo, FoobarImageTag), subjectRef)
ORAS("attach", "--artifact-type", "test.attach", subjectRef, fmt.Sprintf("%s:%s", foobar.AttachFileName, foobar.AttachFileMedia)).
WithWorkDir(tempDir).
MatchStatus([]match.StateKey{foobar.AttachFileStateKey}, false, 1).Exec()
})

It("should attach a file to a subject and export the built manifest", func() {
// prepare
testRepo := attachTestRepo("export-manifest")
tempDir := CopyTestDataToTemp()
exportName := "manifest.json"
subjectRef := Reference(Host, testRepo, FoobarImageTag)
prepare(Reference(Host, ImageRepo, FoobarImageTag), subjectRef)
// test
ORAS("attach", "--artifact-type", "test.attach", subjectRef, fmt.Sprintf("%s:%s", foobar.AttachFileName, foobar.AttachFileMedia), "--export-manifest", exportName).
WithWorkDir(tempDir).
MatchStatus([]match.StateKey{foobar.AttachFileStateKey}, false, 1).Exec()
// validate
var index ocispec.Index
bytes := ORAS("discover", subjectRef, "-o", "json").Exec().Out.Contents()
Expect(json.Unmarshal(bytes, &index)).ShouldNot(HaveOccurred())
Expect(len(index.Manifests)).To(Equal(1))
fetched := ORAS("manifest", "fetch", Reference(Host, testRepo, index.Manifests[0].Digest.String())).Exec().Out.Contents()
MatchFile(filepath.Join(tempDir, exportName), string(fetched), DefaultTimeout)
})
It("should attach a file via a OCI Image", func() {
testRepo := attachTestRepo("image")
tempDir := CopyTestDataToTemp()
subjectRef := Reference(Host, testRepo, FoobarImageTag)
prepare(Reference(Host, ImageRepo, FoobarImageTag), subjectRef)
// test
ORAS("attach", "--artifact-type", "test.attach", subjectRef, fmt.Sprintf("%s:%s", foobar.AttachFileName, foobar.AttachFileMedia), "--image-spec", "v1.1-image").
WithWorkDir(tempDir).
MatchStatus([]match.StateKey{foobar.AttachFileStateKey}, false, 1).Exec()

// validate
var index ocispec.Index
bytes := ORAS("discover", subjectRef, "-o", "json").Exec().Out.Contents()
Expect(json.Unmarshal(bytes, &index)).ShouldNot(HaveOccurred())
Expect(len(index.Manifests)).To(Equal(1))
Expect(index.Manifests[0].MediaType).To(Equal(ocispec.MediaTypeImageManifest))
})
It("should attach a file via a OCI Artifact", func() {
testRepo := attachTestRepo("artifact")
tempDir := CopyTestDataToTemp()
subjectRef := Reference(Host, testRepo, FoobarImageTag)
prepare(Reference(Host, ImageRepo, FoobarImageTag), subjectRef)
// test
ORAS("attach", "--artifact-type", "test.attach", subjectRef, fmt.Sprintf("%s:%s", foobar.AttachFileName, foobar.AttachFileMedia), "--image-spec", "v1.1-artifact").
WithWorkDir(tempDir).
MatchStatus([]match.StateKey{foobar.AttachFileStateKey}, false, 1).Exec()

// validate
var index ocispec.Index
bytes := ORAS("discover", subjectRef, "-o", "json").Exec().Out.Contents()
Expect(json.Unmarshal(bytes, &index)).ShouldNot(HaveOccurred())
Expect(len(index.Manifests)).To(Equal(1))
Expect(index.Manifests[0].MediaType).To(Equal(ocispec.MediaTypeArtifactManifest))
})
})
})

var _ = Describe("Fallback registry users:", func() {
When("running attach command", func() {
It("should attach a file via a OCI Image", func() {
testRepo := attachTestRepo("fallback/image")
tempDir := CopyTestDataToTemp()
subjectRef := Reference(FallbackHost, testRepo, FoobarImageTag)
prepare(Reference(FallbackHost, ArtifactRepo, FoobarImageTag), subjectRef)
// test
ORAS("attach", "--artifact-type", "test.attach", subjectRef, fmt.Sprintf("%s:%s", foobar.AttachFileName, foobar.AttachFileMedia), "--image-spec", "v1.1-image").
WithWorkDir(tempDir).
MatchStatus([]match.StateKey{foobar.AttachFileStateKey}, false, 1).Exec()

// validate
var index ocispec.Index
bytes := ORAS("discover", subjectRef, "-o", "json").Exec().Out.Contents()
Expect(json.Unmarshal(bytes, &index)).ShouldNot(HaveOccurred())
Expect(len(index.Manifests)).To(Equal(1))
Expect(index.Manifests[0].MediaType).To(Equal(ocispec.MediaTypeImageManifest))
})

It("should attach a file via a OCI Image by default", func() {
testRepo := attachTestRepo("fallback/default")
tempDir := CopyTestDataToTemp()
subjectRef := Reference(FallbackHost, testRepo, FoobarImageTag)
prepare(Reference(FallbackHost, ArtifactRepo, FoobarImageTag), subjectRef)
// test
ORAS("attach", "--artifact-type", "test.attach", subjectRef, fmt.Sprintf("%s:%s", foobar.AttachFileName, foobar.AttachFileMedia), "--image-spec", "v1.1-image").
WithWorkDir(tempDir).
MatchStatus([]match.StateKey{foobar.AttachFileStateKey}, false, 1).Exec()

// validate
var index ocispec.Index
bytes := ORAS("discover", subjectRef, "-o", "json").Exec().Out.Contents()
Expect(json.Unmarshal(bytes, &index)).ShouldNot(HaveOccurred())
Expect(len(index.Manifests)).To(Equal(1))
Expect(index.Manifests[0].MediaType).To(Equal(ocispec.MediaTypeImageManifest))
})

It("should attach a file via a OCI Image and generate referrer via tag schema", func() {
testRepo := attachTestRepo("fallback/tag_schema")
tempDir := CopyTestDataToTemp()
subjectRef := Reference(FallbackHost, testRepo, FoobarImageTag)
prepare(Reference(FallbackHost, ArtifactRepo, FoobarImageTag), subjectRef)
// test
ORAS("attach", "--artifact-type", "test.attach", subjectRef, fmt.Sprintf("%s:%s", foobar.AttachFileName, foobar.AttachFileMedia), "--image-spec", "v1.1-image", "--distribution-spec", "v1.1-referrers-tag").
WithWorkDir(tempDir).
MatchStatus([]match.StateKey{foobar.AttachFileStateKey}, false, 1).Exec()

// validate
var index ocispec.Index
bytes := ORAS("discover", subjectRef, "--distribution-spec", "v1.1-referrers-tag", "-o", "json").Exec().Out.Contents()
Expect(json.Unmarshal(bytes, &index)).ShouldNot(HaveOccurred())
Expect(len(index.Manifests)).To(Equal(1))
Expect(index.Manifests[0].MediaType).To(Equal(ocispec.MediaTypeImageManifest))
})
})
})
2 changes: 1 addition & 1 deletion test/e2e/suite/command/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import (
)

func prepare(src string, dst string) {
ORAS("cp", src, dst).Exec()
ORAS("cp", src, dst).WithDescription("prepare test env").Exec()
}

func validate(repoRef string, tag string, gone bool) {
Expand Down
31 changes: 16 additions & 15 deletions test/e2e/suite/scenario/oci_artifact.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"path/filepath"

. "github.com/onsi/ginkgo/v2"
"oras.land/oras/test/e2e/internal/testdata/foobar"
. "oras.land/oras/test/e2e/internal/utils"
"oras.land/oras/test/e2e/internal/utils/match"
)
Expand All @@ -39,20 +40,20 @@ var _ = Describe("Common OCI artifact users:", Ordered, func() {
pulledManifest := "packed.json"
pullRoot := "pulled"
It("should push and pull an artifact", func() {
ORAS("push", Reference(Host, repo, tag), "--artifact-type", "test-artifact", blobFileNames[0], blobFileNames[1], blobFileNames[2], "-v", "--export-manifest", pulledManifest).
MatchStatus(pushFileStateKeys, true, 3).
ORAS("push", Reference(Host, repo, tag), "--artifact-type", "test-artifact", foobar.BlobFileNames[0], foobar.BlobFileNames[1], foobar.BlobFileNames[2], "-v", "--export-manifest", pulledManifest).
MatchStatus(foobar.PushFileStateKeys, true, 3).
WithWorkDir(tempDir).
WithDescription("push with manifest exported").Exec()

fetched := ORAS("manifest", "fetch", Reference(Host, repo, tag)).Exec()
MatchFile(filepath.Join(tempDir, pulledManifest), string(fetched.Out.Contents()), DefaultTimeout)

ORAS("pull", Reference(Host, repo, tag), "-v", "-o", pullRoot).
MatchStatus(pushFileStateKeys, true, 3).
MatchStatus(foobar.PushFileStateKeys, true, 3).
WithWorkDir(tempDir).
WithDescription("pull artFiles with config").Exec()

for _, f := range blobFileNames {
for _, f := range foobar.BlobFileNames {
Binary("diff", filepath.Join(f), filepath.Join(pullRoot, f)).
WithWorkDir(tempDir).
WithDescription("download identical file " + f).Exec()
Expand All @@ -61,40 +62,40 @@ var _ = Describe("Common OCI artifact users:", Ordered, func() {

It("should attach and pull an artifact", func() {
subject := Reference(Host, repo, tag)
ORAS("attach", subject, "--artifact-type", "test.artifact1", fmt.Sprint(attachFileName, ":", attachFileMedia), "-v", "--export-manifest", pulledManifest).
MatchStatus([]match.StateKey{attachFileStateKey}, true, 1).
ORAS("attach", subject, "--artifact-type", "test.artifact1", fmt.Sprint(foobar.AttachFileName, ":", foobar.AttachFileMedia), "-v", "--export-manifest", pulledManifest).
MatchStatus([]match.StateKey{foobar.AttachFileStateKey}, true, 1).
WithWorkDir(tempDir).
WithDescription("attach with manifest exported").Exec()

session := ORAS("discover", subject, "-o", "json").Exec()
digest := string(Binary("jq", "-r", ".manifests[].digest").WithInput(session.Out).Exec().Out.Contents())
fetched := ORAS("manifest", "fetch", Reference(Host, repo, digest)).MatchKeyWords(attachFileMedia).Exec()
fetched := ORAS("manifest", "fetch", Reference(Host, repo, digest)).MatchKeyWords(foobar.AttachFileMedia).Exec()
MatchFile(filepath.Join(tempDir, pulledManifest), string(fetched.Out.Contents()), DefaultTimeout)

ORAS("pull", Reference(Host, repo, digest), "-v", "-o", pullRoot).
MatchStatus([]match.StateKey{attachFileStateKey}, true, 1).
MatchStatus([]match.StateKey{foobar.AttachFileStateKey}, true, 1).
WithWorkDir(tempDir).
WithDescription("pull attached artifact").Exec()
Binary("diff", filepath.Join(attachFileName), filepath.Join(pullRoot, attachFileName)).
Binary("diff", filepath.Join(foobar.AttachFileName), filepath.Join(pullRoot, foobar.AttachFileName)).
WithWorkDir(tempDir).
WithDescription("download identical file " + attachFileName).Exec()
WithDescription("download identical file " + foobar.AttachFileName).Exec()

ORAS("attach", subject, "--artifact-type", "test.artifact2", fmt.Sprint(attachFileName, ":", attachFileMedia), "-v", "--export-manifest", pulledManifest).
MatchStatus([]match.StateKey{attachFileStateKey}, true, 1).
ORAS("attach", subject, "--artifact-type", "test.artifact2", fmt.Sprint(foobar.AttachFileName, ":", foobar.AttachFileMedia), "-v", "--export-manifest", pulledManifest).
MatchStatus([]match.StateKey{foobar.AttachFileStateKey}, true, 1).
WithWorkDir(tempDir).
WithDescription("attach again with manifest exported").Exec()

session = ORAS("discover", subject, "-o", "json", "--artifact-type", "test.artifact2").Exec()
digest = string(Binary("jq", "-r", ".manifests[].digest").WithInput(session.Out).Exec().Out.Contents())
fetched = ORAS("manifest", "fetch", Reference(Host, repo, digest)).MatchKeyWords(attachFileMedia).Exec()
fetched = ORAS("manifest", "fetch", Reference(Host, repo, digest)).MatchKeyWords(foobar.AttachFileMedia).Exec()
MatchFile(filepath.Join(tempDir, pulledManifest), string(fetched.Out.Contents()), DefaultTimeout)

ORAS("pull", Reference(Host, repo, string(digest)), "-v", "-o", pullRoot, "--include-subject").
MatchStatus(append(pushFileStateKeys, attachFileStateKey), true, 4).
MatchStatus(append(foobar.PushFileStateKeys, foobar.AttachFileStateKey), true, 4).
WithWorkDir(tempDir).
WithDescription("pull attached artifact and subject").Exec()

for _, f := range append(blobFileNames, attachFileName) {
for _, f := range append(foobar.BlobFileNames, foobar.AttachFileName) {
Binary("diff", filepath.Join(f), filepath.Join(pullRoot, f)).
WithWorkDir(tempDir).
WithDescription("download identical file " + f).Exec()
Expand Down
5 changes: 3 additions & 2 deletions test/e2e/suite/scenario/oci_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ import (
"path/filepath"

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

var _ = Describe("OCI image user:", Ordered, func() {
repo := "scenario/oci-image"
files := append([]string{configFileName}, blobFileNames...)
statusKeys := append(pushFileStateKeys, configFileStateKey)
files := append([]string{foobar.ConfigFileName}, foobar.BlobFileNames...)
statusKeys := append(foobar.PushFileStateKeys, foobar.ConfigFileStateKey)
When("pushing images and check", func() {
tag := "image"
var tempDir string
Expand Down