From a22b7826f00a25d64c1a8d89e92b7227d69ee331 Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Fri, 1 Sep 2023 15:07:10 +0800 Subject: [PATCH] test(e2e): add tests to cover OCI spec v1.1.0-rc.4 and OCI distribution spec 1.1.0-rc3 (#1099) Signed-off-by: Billy Zha --- .../internal/testdata/artifact/blob/const.go | 30 ++++ .../testdata/artifact/config/const.go | 30 ++++ test/e2e/internal/testdata/artifact/const.go | 36 +++++ .../internal/testdata/artifact/index/const.go | 26 ++++ .../e2e/internal/testdata/multi_arch/const.go | 1 + test/e2e/suite/command/cp.go | 35 ++++- test/e2e/suite/command/pull.go | 67 ++++++++- test/e2e/suite/command/push.go | 130 ++++++++++++++++-- ...49df19dbef6ad10c0e1c2882241e3fedfe20f012a3 | 1 + ...50a993db98a6df7a6cc77a35c388908a3a50be6bad | 1 + ...2b948eb846c968511ae02724672d608f3d05bc61a1 | 1 + .../testdata/zot/command/artifacts/index.json | 21 +++ 12 files changed, 357 insertions(+), 22 deletions(-) create mode 100644 test/e2e/internal/testdata/artifact/blob/const.go create mode 100644 test/e2e/internal/testdata/artifact/config/const.go create mode 100644 test/e2e/internal/testdata/artifact/const.go create mode 100644 test/e2e/internal/testdata/artifact/index/const.go create mode 100644 test/e2e/testdata/zot/command/artifacts/blobs/sha256/0e7404d1cc4a2115fdd83449df19dbef6ad10c0e1c2882241e3fedfe20f012a3 create mode 100644 test/e2e/testdata/zot/command/artifacts/blobs/sha256/7679bc22c33b87aa345c6950a993db98a6df7a6cc77a35c388908a3a50be6bad create mode 100644 test/e2e/testdata/zot/command/artifacts/blobs/sha256/ccd5f15fb7e0d27d47e2912b948eb846c968511ae02724672d608f3d05bc61a1 diff --git a/test/e2e/internal/testdata/artifact/blob/const.go b/test/e2e/internal/testdata/artifact/blob/const.go new file mode 100644 index 000000000..78e37c3c5 --- /dev/null +++ b/test/e2e/internal/testdata/artifact/blob/const.go @@ -0,0 +1,30 @@ +/* +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 blob + +import "oras.land/oras/test/e2e/internal/utils/match" + +const ( + Tag = "blob" +) + +var ( + StateKeys = []match.StateKey{ + {Digest: "44136fa355b3", Name: "application/vnd.oci.empty.v1+json"}, + {Digest: "2ef548696ac7", Name: "hello.tar"}, + {Digest: "ccd5f15fb7e0", Name: "application/vnd.oci.image.manifest.v1+json"}, + } +) diff --git a/test/e2e/internal/testdata/artifact/config/const.go b/test/e2e/internal/testdata/artifact/config/const.go new file mode 100644 index 000000000..6e9765964 --- /dev/null +++ b/test/e2e/internal/testdata/artifact/config/const.go @@ -0,0 +1,30 @@ +/* +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 config + +import "oras.land/oras/test/e2e/internal/utils/match" + +const ( + Tag = "config" +) + +var ( + StateKeys = []match.StateKey{ + {Digest: "fe9dbc99451d", Name: "application/vnd.oci.image.config.v1+json"}, + {Digest: "2ef548696ac7", Name: "hello.tar"}, + {Digest: "0e7404d1cc4a", Name: "application/vnd.oci.image.manifest.v1+json"}, + } +) diff --git a/test/e2e/internal/testdata/artifact/const.go b/test/e2e/internal/testdata/artifact/const.go new file mode 100644 index 000000000..b71c3605b --- /dev/null +++ b/test/e2e/internal/testdata/artifact/const.go @@ -0,0 +1,36 @@ +/* +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 artifact + +import ( + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "oras.land/oras/test/e2e/internal/utils/match" +) + +const ( + DefaultArtifactType = "application/vnd.unknown.artifact.v1" + DefaultConfigMediaType = "application/vnd.oci.empty.v1+json" +) + +var ( + DefaultConfigStateKey = match.StateKey{Digest: "44136fa355b3", Name: "application/vnd.oci.empty.v1+json"} + EmptyLayerJSON = ocispec.Descriptor{ + MediaType: "application/vnd.oci.empty.v1+json", + Digest: "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a", + Size: 2, + Data: []byte(`{}`), + } +) diff --git a/test/e2e/internal/testdata/artifact/index/const.go b/test/e2e/internal/testdata/artifact/index/const.go new file mode 100644 index 000000000..5fdb41ed0 --- /dev/null +++ b/test/e2e/internal/testdata/artifact/index/const.go @@ -0,0 +1,26 @@ +/* +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 index + +import "oras.land/oras/test/e2e/internal/utils/match" + +var ( + ManifestDigest = "sha256:7679bc22c33b87aa345c6950a993db98a6df7a6cc77a35c388908a3a50be6bad" + ManifestStatusKey = match.StateKey{ + Digest: "7679bc22c33b", + Name: "application/vnd.oci.image.index.v1+json", + } +) diff --git a/test/e2e/internal/testdata/multi_arch/const.go b/test/e2e/internal/testdata/multi_arch/const.go index 94cd9ef59..119764386 100644 --- a/test/e2e/internal/testdata/multi_arch/const.go +++ b/test/e2e/internal/testdata/multi_arch/const.go @@ -34,6 +34,7 @@ var ( {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"}, + {Digest: "e2bfc9cc6a84", Name: "application/vnd.oci.image.index.v1+json"}, } // below are newly baked artifacts for ZOT IndexZOTReferrerStateKey = match.StateKey{Digest: "d37baf66300b", Name: "application/vnd.oci.image.manifest.v1+json"} diff --git a/test/e2e/suite/command/cp.go b/test/e2e/suite/command/cp.go index b0e67cc16..317d0f989 100644 --- a/test/e2e/suite/command/cp.go +++ b/test/e2e/suite/command/cp.go @@ -27,6 +27,9 @@ import ( "github.com/onsi/gomega/gbytes" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "oras.land/oras-go/v2" + "oras.land/oras/test/e2e/internal/testdata/artifact/blob" + "oras.land/oras/test/e2e/internal/testdata/artifact/config" + "oras.land/oras/test/e2e/internal/testdata/artifact/index" "oras.land/oras/test/e2e/internal/testdata/feature" "oras.land/oras/test/e2e/internal/testdata/foobar" ma "oras.land/oras/test/e2e/internal/testdata/multi_arch" @@ -70,9 +73,29 @@ func CompareRef(src, dst string) { var _ = Describe("1.1 registry users:", func() { When("running `cp`", func() { + It("should copy an artifact with blob", func() { + src := RegistryRef(ZOTHost, ArtifactRepo, blob.Tag) + dst := RegistryRef(ZOTHost, cpTestRepo("artifact-with-blob"), "copied") + ORAS("cp", src, dst, "-v").MatchStatus(blob.StateKeys, true, len(blob.StateKeys)).Exec() + CompareRef(src, dst) + }) + + It("should copy an artifact with config", func() { + src := RegistryRef(ZOTHost, ArtifactRepo, config.Tag) + dst := RegistryRef(ZOTHost, cpTestRepo("artifact-with-config"), "copied") + ORAS("cp", src, dst, "-v").MatchStatus(config.StateKeys, true, len(config.StateKeys)).Exec() + }) + + It("should copy index and its subject", func() { + stateKeys := append(ma.IndexStateKeys, index.ManifestStatusKey) + src := RegistryRef(ZOTHost, ArtifactRepo, index.ManifestDigest) + dst := RegistryRef(ZOTHost, cpTestRepo("index-with-subject"), "") + ORAS("cp", src, dst, "-v").MatchStatus(stateKeys, true, len(stateKeys)).Exec() + }) + It("should copy an image to a new repository via tag", func() { src := RegistryRef(ZOTHost, ImageRepo, foobar.Tag) - dst := RegistryRef(ZOTHost, cpTestRepo("tag"), "copiedTag") + dst := RegistryRef(ZOTHost, cpTestRepo("tag"), "copied") ORAS("cp", src, dst, "-v").MatchStatus(foobarStates, true, len(foobarStates)).Exec() CompareRef(src, dst) }) @@ -111,7 +134,7 @@ var _ = Describe("1.1 registry users:", func() { // validate CompareRef(RegistryRef(ZOTHost, ImageRepo, ma.Digest), dst) var index ocispec.Index - bytes := ORAS("discover", dst, "-o", "json"). + bytes := ORAS("discover", dst, "-o", "json", "--artifact-type", ma.IndexReferrerConfigStateKey.Name). MatchKeyWords(ma.IndexReferrerDigest). WithDescription("copy image referrer"). Exec().Out.Contents() @@ -136,7 +159,7 @@ var _ = Describe("1.1 registry users:", func() { // validate CompareRef(RegistryRef(ZOTHost, ImageRepo, ma.Digest), dst) var index ocispec.Index - bytes := ORAS("discover", dst, "-o", "json"). + bytes := ORAS("discover", dst, "-o", "json", "--artifact-type", ma.IndexReferrerConfigStateKey.Name). MatchKeyWords(ma.IndexReferrerDigest). WithDescription("copy image referrer"). Exec().Out.Contents() @@ -454,8 +477,8 @@ var _ = Describe("OCI layout users:", func() { dstManifest := ORAS("manifest", "fetch", dst, Flags.Layout).WithDescription("fetch from destination to validate").Exec().Out.Contents() Expect(srcManifest).To(Equal(dstManifest)) var index ocispec.Index - bytes := ORAS("discover", dst, "-o", "json", Flags.Layout). - MatchKeyWords(ma.IndexReferrerDigest). + bytes := ORAS("discover", dst, "-o", "json", Flags.Layout, "--artifact-type", ma.IndexReferrerConfigStateKey.Name). + // MatchKeyWords(ma.IndexReferrerDigest). WithDescription("copy image referrer"). Exec().Out.Contents() Expect(json.Unmarshal(bytes, &index)).ShouldNot(HaveOccurred()) @@ -484,7 +507,7 @@ var _ = Describe("OCI layout users:", func() { dstManifest := ORAS("manifest", "fetch", dst).WithDescription("fetch from destination to validate").Exec().Out.Contents() Expect(srcManifest).To(Equal(dstManifest)) var index ocispec.Index - bytes := ORAS("discover", dst, "-o", "json"). + bytes := ORAS("discover", dst, "-o", "json", "--artifact-type", ma.IndexReferrerConfigStateKey.Name). MatchKeyWords(ma.IndexReferrerDigest). WithDescription("copy image referrer"). Exec().Out.Contents() diff --git a/test/e2e/suite/command/pull.go b/test/e2e/suite/command/pull.go index d219af7c5..8bf6c1225 100644 --- a/test/e2e/suite/command/pull.go +++ b/test/e2e/suite/command/pull.go @@ -26,6 +26,8 @@ import ( . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" "oras.land/oras-go/v2" + "oras.land/oras/test/e2e/internal/testdata/artifact/blob" + "oras.land/oras/test/e2e/internal/testdata/artifact/config" "oras.land/oras/test/e2e/internal/testdata/feature" "oras.land/oras/test/e2e/internal/testdata/foobar" "oras.land/oras/test/e2e/internal/testdata/multi_arch" @@ -41,7 +43,7 @@ var _ = Describe("ORAS beginners:", func() { }) }) -var _ = Describe("Remote registry users:", func() { +var _ = Describe("OCI spec 1.1 registry users:", func() { When("pulling images from remote registry", func() { var ( configName = "test.config" @@ -105,6 +107,69 @@ var _ = Describe("Remote registry users:", func() { ORAS("pull", RegistryRef(ZOTHost, ImageRepo, "multi"), "--platform", "linux/amd64", "-v", "-o", GinkgoT().TempDir()). MatchStatus(multi_arch.LinuxAMD64StateKeys, true, len(multi_arch.LinuxAMD64StateKeys)).Exec() }) + + It("should pull an artifact with blob", func() { + pullRoot := GinkgoT().TempDir() + ORAS("pull", RegistryRef(ZOTHost, ArtifactRepo, blob.Tag), "-v", "-o", pullRoot).Exec() + Expect(filepath.Join(pullRoot, multi_arch.LayerName)).Should(BeAnExistingFile()) + }) + + It("should pull an artifact with config", func() { + pullRoot := GinkgoT().TempDir() + ORAS("pull", RegistryRef(ZOTHost, ArtifactRepo, config.Tag), "-v", "-o", pullRoot).Exec() + Expect(filepath.Join(pullRoot, multi_arch.LayerName)).Should(BeAnExistingFile()) + }) + + It("should copy an artifact with blob", func() { + repo := cpTestRepo("artifact-with-blob") + stateKeys := append(append(foobarStates, foobar.ImageReferrersStateKeys...), foobar.ImageReferrerConfigStateKeys...) + src := RegistryRef(ZOTHost, ArtifactRepo, foobar.SignatureImageReferrer.Digest.String()) + dst := RegistryRef(FallbackHost, repo, "") + ORAS("cp", "-r", src, dst, "-v").MatchStatus(stateKeys, true, len(stateKeys)).Exec() + CompareRef(src, RegistryRef(FallbackHost, repo, foobar.SignatureImageReferrer.Digest.String())) + ORAS("discover", "-o", "tree", RegistryRef(FallbackHost, repo, foobar.Digest)). + WithDescription("discover referrer via subject").MatchKeyWords(foobar.SignatureImageReferrer.Digest.String(), foobar.SBOMImageReferrer.Digest.String()).Exec() + }) + }) +}) + +var _ = Describe("OCI spec 1.0 registry users:", func() { + It("should pull all files in an image to a target folder", func() { + pullRoot := "pulled" + configName := "test.config" + tempDir := PrepareTempFiles() + stateKeys := append(foobar.ImageLayerStateKeys, foobar.ManifestStateKey, foobar.ImageConfigStateKey(configName)) + ORAS("pull", RegistryRef(FallbackHost, ArtifactRepo, foobar.Tag), "-v", "--config", configName, "-o", pullRoot). + MatchStatus(stateKeys, true, len(stateKeys)). + WithWorkDir(tempDir).Exec() + // check config + configPath := filepath.Join(tempDir, pullRoot, configName) + Expect(configPath).Should(BeAnExistingFile()) + f, err := os.Open(configPath) + Expect(err).ShouldNot(HaveOccurred()) + defer f.Close() + Eventually(gbytes.BufferReader(f)).Should(gbytes.Say("{}")) + for _, f := range foobar.ImageLayerNames { + // check layers + Binary("diff", filepath.Join(tempDir, "foobar", f), filepath.Join(pullRoot, f)). + WithWorkDir(tempDir).Exec() + } + + ORAS("pull", RegistryRef(FallbackHost, ArtifactRepo, foobar.Tag), "-v", "-o", pullRoot, "--keep-old-files"). + ExpectFailure(). + WithDescription("fail if overwrite old files are disabled") + }) + + It("should pull subject", func() { + tempDir := GinkgoT().TempDir() + stateKeys := append(append( + foobar.ImageLayerStateKeys, + foobar.ManifestStateKey), + foobar.ImageReferrersStateKeys..., + ) + ORAS("pull", RegistryRef(FallbackHost, ArtifactRepo, foobar.SignatureImageReferrer.Digest.String()), "-v", "--include-subject"). + MatchStatus(stateKeys, true, len(stateKeys)). + WithWorkDir(tempDir).Exec() }) }) diff --git a/test/e2e/suite/command/push.go b/test/e2e/suite/command/push.go index e10d47f3a..3aba4fcb4 100644 --- a/test/e2e/suite/command/push.go +++ b/test/e2e/suite/command/push.go @@ -27,6 +27,7 @@ import ( "github.com/onsi/gomega/gbytes" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "oras.land/oras/test/e2e/internal/testdata/artifact" "oras.land/oras/test/e2e/internal/testdata/feature" "oras.land/oras/test/e2e/internal/testdata/foobar" . "oras.land/oras/test/e2e/internal/utils" @@ -39,19 +40,30 @@ var _ = Describe("ORAS beginners:", func() { out := ORAS("push", "--help").MatchKeyWords(ExampleDesc).Exec().Out gomega.Expect(out).Should(gbytes.Say("--image-spec string\\s+%s", regexp.QuoteMeta(feature.Experimental.Mark))) }) + + It("should fail to use --config and --artifact-type at the same time for OCI spec v1.0 registry", func() { + tempDir := PrepareTempFiles() + repo := pushTestRepo("no-mediatype") + ref := RegistryRef(ZOTHost, repo, "") + + ORAS("push", ref, "--config", foobar.FileConfigName, "--artifact-type", "test/artifact+json", "--image-spec", "v1.0").ExpectFailure().WithWorkDir(tempDir).Exec() + }) }) }) -var _ = Describe("1.1 registry users:", func() { +func pushTestRepo(text string) string { + return fmt.Sprintf("command/push/%d/%s", GinkgoRandomSeed(), text) +} + +var _ = Describe("Remote registry users:", func() { tag := "e2e" - When("pushing to registy without OCI artifact support", func() { - repoPrefix := fmt.Sprintf("command/push/%d", GinkgoRandomSeed()) + When("pushing to OCI spec v1.0 registries", func() { statusKeys := []match.StateKey{ foobar.ImageConfigStateKey("application/vnd.oci.empty.v1+json"), foobar.FileBarStateKey, } It("should push files without customized media types", func() { - repo := fmt.Sprintf("%s/%s", repoPrefix, "no-mediatype") + repo := pushTestRepo("no-mediatype") tempDir := PrepareTempFiles() ref := RegistryRef(ZOTHost, repo, tag) @@ -67,7 +79,7 @@ var _ = Describe("1.1 registry users:", func() { }) It("should push files with path validation disabled", func() { - repo := fmt.Sprintf("%s/%s", repoPrefix, "disable-path-validation") + repo := pushTestRepo("disable-path-validation") ref := RegistryRef(ZOTHost, repo, tag) absBarName := filepath.Join(PrepareTempFiles(), foobar.FileBarName) @@ -89,7 +101,7 @@ var _ = Describe("1.1 registry users:", func() { }) It("should fail path validation when pushing file with absolute path", func() { - repo := fmt.Sprintf("%s/%s", repoPrefix, "path-validation") + repo := pushTestRepo("path-validation") ref := RegistryRef(ZOTHost, repo, tag) absBarName := filepath.Join(PrepareTempFiles(), foobar.FileBarName) // test @@ -100,7 +112,7 @@ var _ = Describe("1.1 registry users:", func() { }) It("should push files and tag", func() { - repo := fmt.Sprintf("%s/%s", repoPrefix, "multi-tag") + repo := pushTestRepo("multi-tag") tempDir := PrepareTempFiles() extraTag := "2e2" @@ -120,7 +132,7 @@ var _ = Describe("1.1 registry users:", func() { }) It("should push files with customized media types", func() { - repo := fmt.Sprintf("%s/%s", repoPrefix, "layer-mediatype") + repo := pushTestRepo("layer-mediatype") layerType := "layer/type" tempDir := PrepareTempFiles() ORAS("push", RegistryRef(ZOTHost, repo, tag), foobar.FileBarName+":"+layerType, "-v"). @@ -134,7 +146,7 @@ var _ = Describe("1.1 registry users:", func() { }) It("should push files with manifest exported", func() { - repo := fmt.Sprintf("%s/%s", repoPrefix, "export-manifest") + repo := pushTestRepo("export-manifest") layerType := "layer/type" tempDir := PrepareTempFiles() exportPath := "packed.json" @@ -147,7 +159,7 @@ var _ = Describe("1.1 registry users:", func() { }) It("should push files with customized config file", func() { - repo := fmt.Sprintf("%s/%s", repoPrefix, "config") + repo := pushTestRepo("config") tempDir := PrepareTempFiles() ORAS("push", RegistryRef(ZOTHost, repo, tag), "--config", foobar.FileConfigName, foobar.FileBarName, "-v"). @@ -168,13 +180,13 @@ var _ = Describe("1.1 registry users:", func() { }) It("should push files with customized config file and mediatype", func() { - repo := fmt.Sprintf("%s/%s", repoPrefix, "config/mediatype") + repo := pushTestRepo("config/mediatype") configType := "config/type" tempDir := PrepareTempFiles() ORAS("push", RegistryRef(ZOTHost, repo, tag), "--config", fmt.Sprintf("%s:%s", foobar.FileConfigName, configType), foobar.FileBarName, "-v"). MatchStatus([]match.StateKey{ - {Digest: "46b68ac1696c", Name: configType}, + {Digest: foobar.FileConfigStateKey.Digest, Name: configType}, foobar.FileBarStateKey, }, true, 2). WithWorkDir(tempDir).Exec() @@ -190,7 +202,7 @@ var _ = Describe("1.1 registry users:", func() { }) It("should push files with customized manifest annotation", func() { - repo := fmt.Sprintf("%s/%s", repoPrefix, "manifest-annotation") + repo := pushTestRepo("manifest-annotation") key := "image-anno-key" value := "image-anno-value" tempDir := PrepareTempFiles() @@ -206,7 +218,7 @@ var _ = Describe("1.1 registry users:", func() { }) It("should push files with customized file annotation", func() { - repo := fmt.Sprintf("%s/%s", repoPrefix, "file-annotation") + repo := pushTestRepo("file-annotation") tempDir := PrepareTempFiles() ORAS("push", RegistryRef(ZOTHost, repo, tag), foobar.FileBarName, "-v", "--annotation-file", "foobar/annotation.json", "--config", foobar.FileConfigName). @@ -224,6 +236,94 @@ var _ = Describe("1.1 registry users:", func() { Expect(manifest.Layers[0].Annotations["foo"]).To(Equal("bar")) }) }) + + When("pushing to OCI spec v1.1 registries", func() { + It("should push artifact without layer", func() { + repo := pushTestRepo("artifact-no-layer") + tempDir := PrepareTempFiles() + artifactType := "test/artifact+json" + annotationKey := "key" + annotationValue := "value" + + // test + ORAS("push", RegistryRef(ZOTHost, repo, tag), "-a", fmt.Sprintf("%s=%s", annotationKey, annotationValue), "-v", "--artifact-type", artifactType). + MatchStatus([]match.StateKey{artifact.DefaultConfigStateKey}, true, 1). + WithWorkDir(tempDir).Exec() + + // validate + fetched := ORAS("manifest", "fetch", RegistryRef(ZOTHost, repo, tag)).Exec().Out.Contents() + var manifest ocispec.Manifest + Expect(json.Unmarshal(fetched, &manifest)).ShouldNot(HaveOccurred()) + Expect(manifest.ArtifactType).Should(Equal(artifactType)) + Expect(manifest.Layers).Should(HaveLen(1)) + Expect(manifest.Layers[0]).Should(Equal(artifact.EmptyLayerJSON)) + Expect(manifest.Config).Should(Equal(artifact.EmptyLayerJSON)) + Expect(manifest.Annotations).NotTo(BeNil()) + Expect(manifest.Annotations[annotationKey]).Should(Equal(annotationValue)) + }) + + It("should push artifact with blob", func() { + repo := pushTestRepo("artifact-with-blob") + tempDir := PrepareTempFiles() + + ORAS("push", RegistryRef(ZOTHost, repo, tag), foobar.FileBarName, "-v"). + MatchStatus([]match.StateKey{foobar.FileBarStateKey, artifact.DefaultConfigStateKey}, true, 2). + WithWorkDir(tempDir).Exec() + + // validate + fetched := ORAS("manifest", "fetch", RegistryRef(ZOTHost, repo, tag)).Exec().Out.Contents() + var manifest ocispec.Manifest + Expect(json.Unmarshal(fetched, &manifest)).ShouldNot(HaveOccurred()) + Expect(manifest.ArtifactType).Should(Equal(artifact.DefaultArtifactType)) + Expect(manifest.Layers).Should(ContainElements(foobar.BlobBarDescriptor("application/vnd.oci.image.layer.v1.tar"))) + Expect(manifest.Config).Should(Equal(artifact.EmptyLayerJSON)) + }) + + It("should push artifact with config", func() { + repo := pushTestRepo("artifact-with-config") + tempDir := PrepareTempFiles() + configType := "test/config+json" + + ORAS("push", RegistryRef(ZOTHost, repo, tag), foobar.FileBarName, "--config", fmt.Sprintf("%s:%s", foobar.FileConfigName, configType), "-v"). + MatchStatus([]match.StateKey{ + foobar.FileBarStateKey, + {Digest: foobar.FileConfigStateKey.Digest, Name: configType}, + artifact.DefaultConfigStateKey}, true, 2). + WithWorkDir(tempDir).Exec() + + // validate + fetched := ORAS("manifest", "fetch", RegistryRef(ZOTHost, repo, tag)).Exec().Out.Contents() + var manifest ocispec.Manifest + Expect(json.Unmarshal(fetched, &manifest)).ShouldNot(HaveOccurred()) + Expect(manifest.ArtifactType).Should(Equal("")) + Expect(manifest.Layers).Should(ContainElements(foobar.BlobBarDescriptor("application/vnd.oci.image.layer.v1.tar"))) + Expect(manifest.Config.MediaType).Should(Equal(configType)) + Expect(manifest.Config.Digest).Should(Equal(foobar.FileConfigDigest)) + }) + + It("should push artifact with artifact type and config data", func() { + repo := pushTestRepo("artifact-type-and-config") + tempDir := PrepareTempFiles() + artifactType := "test/artifact+json" + configType := "test/config+json" + + ORAS("push", RegistryRef(ZOTHost, repo, tag), foobar.FileBarName, "--artifact-type", artifactType, "--config", fmt.Sprintf("%s:%s", foobar.FileConfigName, configType), "-v"). + MatchStatus([]match.StateKey{ + foobar.FileBarStateKey, + {Digest: foobar.FileConfigStateKey.Digest, Name: configType}, + artifact.DefaultConfigStateKey}, true, 2). + WithWorkDir(tempDir).Exec() + + // validate + fetched := ORAS("manifest", "fetch", RegistryRef(ZOTHost, repo, tag)).Exec().Out.Contents() + var manifest ocispec.Manifest + Expect(json.Unmarshal(fetched, &manifest)).ShouldNot(HaveOccurred()) + Expect(manifest.ArtifactType).Should(Equal(artifactType)) + Expect(manifest.Layers).Should(ContainElements(foobar.BlobBarDescriptor("application/vnd.oci.image.layer.v1.tar"))) + Expect(manifest.Config.MediaType).Should(Equal(configType)) + Expect(manifest.Config.Digest).Should(Equal(foobar.FileConfigDigest)) + }) + }) }) var _ = Describe("OCI image layout users:", func() { @@ -321,7 +421,7 @@ var _ = Describe("OCI image layout users:", func() { ref := LayoutRef(tempDir, tag) ORAS("push", Flags.Layout, ref, "--config", fmt.Sprintf("%s:%s", foobar.FileConfigName, configType), foobar.FileBarName, "-v"). MatchStatus([]match.StateKey{ - {Digest: "46b68ac1696c", Name: configType}, + {Digest: foobar.FileConfigStateKey.Digest, Name: configType}, foobar.FileBarStateKey, }, true, 2). WithWorkDir(tempDir).Exec() diff --git a/test/e2e/testdata/zot/command/artifacts/blobs/sha256/0e7404d1cc4a2115fdd83449df19dbef6ad10c0e1c2882241e3fedfe20f012a3 b/test/e2e/testdata/zot/command/artifacts/blobs/sha256/0e7404d1cc4a2115fdd83449df19dbef6ad10c0e1c2882241e3fedfe20f012a3 new file mode 100644 index 000000000..7b756994e --- /dev/null +++ b/test/e2e/testdata/zot/command/artifacts/blobs/sha256/0e7404d1cc4a2115fdd83449df19dbef6ad10c0e1c2882241e3fedfe20f012a3 @@ -0,0 +1 @@ +{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","artifactType":"application/vnd.example+type","config":{"mediaType":"application/vnd.oci.image.config.v1+json","digest":"sha256:fe9dbc99451d0517d65e048c309f0b5afb2cc513b7a3d456b6cc29fe641386c5","size":53},"layers":[{"mediaType":"application/vnd.oci.image.layer.v1.tar","digest":"sha256:2ef548696ac7dd66ef38aab5cc8fc5cc1fb637dfaedb3a9afc89bf16db9277e1","size":10240,"annotations":{"org.opencontainers.image.title":"hello.tar"}}]} diff --git a/test/e2e/testdata/zot/command/artifacts/blobs/sha256/7679bc22c33b87aa345c6950a993db98a6df7a6cc77a35c388908a3a50be6bad b/test/e2e/testdata/zot/command/artifacts/blobs/sha256/7679bc22c33b87aa345c6950a993db98a6df7a6cc77a35c388908a3a50be6bad new file mode 100644 index 000000000..af8273869 --- /dev/null +++ b/test/e2e/testdata/zot/command/artifacts/blobs/sha256/7679bc22c33b87aa345c6950a993db98a6df7a6cc77a35c388908a3a50be6bad @@ -0,0 +1 @@ +{"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"}}],"subject":{"mediaType":"application/vnd.oci.image.index.v1+json","digest":"sha256:e2bfc9cc6a84ec2d7365b5a28c6bc5806b7fa581c9ad7883be955a64e3cc034f","size":706}} diff --git a/test/e2e/testdata/zot/command/artifacts/blobs/sha256/ccd5f15fb7e0d27d47e2912b948eb846c968511ae02724672d608f3d05bc61a1 b/test/e2e/testdata/zot/command/artifacts/blobs/sha256/ccd5f15fb7e0d27d47e2912b948eb846c968511ae02724672d608f3d05bc61a1 new file mode 100644 index 000000000..33b73c855 --- /dev/null +++ b/test/e2e/testdata/zot/command/artifacts/blobs/sha256/ccd5f15fb7e0d27d47e2912b948eb846c968511ae02724672d608f3d05bc61a1 @@ -0,0 +1 @@ +{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","artifactType":"application/vnd.example+type","config":{"mediaType":"application/vnd.oci.empty.v1+json","digest":"sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a","size":2},"layers":[{"mediaType":"application/vnd.oci.image.layer.v1.tar","digest":"sha256:2ef548696ac7dd66ef38aab5cc8fc5cc1fb637dfaedb3a9afc89bf16db9277e1","size":10240,"annotations":{"org.opencontainers.image.title":"hello.tar"}}],"annotations":{"org.opencontainers.image.created":"2023-08-03T00:21:51Z"}} diff --git a/test/e2e/testdata/zot/command/artifacts/index.json b/test/e2e/testdata/zot/command/artifacts/index.json index 09c536779..58f824e70 100644 --- a/test/e2e/testdata/zot/command/artifacts/index.json +++ b/test/e2e/testdata/zot/command/artifacts/index.json @@ -56,6 +56,27 @@ "mediaType": "application/vnd.oci.image.manifest.v1+json", "digest": "sha256:c5e00045954a70e3fd28307dd543d4cc158946117943700b8f520f72ddca031f", "size": 482 + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:ccd5f15fb7e0d27d47e2912b948eb846c968511ae02724672d608f3d05bc61a1", + "size": 571, + "annotations": { + "org.opencontainers.image.ref.name": "blob" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:0e7404d1cc4a2115fdd83449df19dbef6ad10c0e1c2882241e3fedfe20f012a3", + "size": 505, + "annotations": { + "org.opencontainers.image.ref.name": "config" + } + }, + { + "mediaType": "application/vnd.oci.image.index.v1+json", + "digest": "sha256:7679bc22c33b87aa345c6950a993db98a6df7a6cc77a35c388908a3a50be6bad", + "size": 867 } ] } \ No newline at end of file