From cedd16dad7d9b59dd21b0391e67ce9ce393e6376 Mon Sep 17 00:00:00 2001 From: Billy Zha Date: Mon, 27 Feb 2023 19:25:49 +0800 Subject: [PATCH] test(e2e): add specs for `oras discover` (#828) Signed-off-by: Billy Zha --- test/e2e/go.mod | 10 +- test/e2e/go.sum | 30 ++- test/e2e/internal/testdata/foobar/const.go | 57 +++++- .../e2e/internal/testdata/multi_arch/const.go | 28 ++- test/e2e/suite/command/cp.go | 42 ++--- test/e2e/suite/command/discover.go | 175 ++++++++++++++++++ test/e2e/suite/command/manifest.go | 16 +- 7 files changed, 307 insertions(+), 51 deletions(-) create mode 100644 test/e2e/suite/command/discover.go diff --git a/test/e2e/go.mod b/test/e2e/go.mod index 3e9a8829d..e462d6bec 100644 --- a/test/e2e/go.mod +++ b/test/e2e/go.mod @@ -3,19 +3,23 @@ module oras.land/oras/test/e2e go 1.20 require ( - github.com/onsi/ginkgo/v2 v2.8.1 - github.com/onsi/gomega v1.26.0 + github.com/onsi/ginkgo/v2 v2.8.3 + github.com/onsi/gomega v1.27.0 + github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0-rc2 + gopkg.in/yaml.v2 v2.4.0 oras.land/oras-go/v2 v2.0.0 ) require ( github.com/go-logr/logr v1.2.3 // indirect + github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/google/go-cmp v0.5.9 // indirect - github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect golang.org/x/net v0.7.0 // indirect golang.org/x/sync v0.1.0 // indirect golang.org/x/sys v0.5.0 // indirect golang.org/x/text v0.7.0 // indirect + golang.org/x/tools v0.6.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/test/e2e/go.sum b/test/e2e/go.sum index 859ca432b..72d4f8362 100644 --- a/test/e2e/go.sum +++ b/test/e2e/go.sum @@ -1,27 +1,49 @@ +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/onsi/ginkgo/v2 v2.8.1 h1:xFTEVwOFa1D/Ty24Ws1npBWkDYEV9BqZrsDxVrVkrrU= -github.com/onsi/ginkgo/v2 v2.8.1/go.mod h1:N1/NbDngAFcSLdyZ+/aYTYGSlq9qMCS/cNKGJjy+csc= -github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q= -github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/onsi/ginkgo/v2 v2.8.3 h1:RpbK1G8nWPNaCVFBWsOGnEQQGgASi6b8fxcWBvDYjxQ= +github.com/onsi/ginkgo/v2 v2.8.3/go.mod h1:6OaUA8BCi0aZfmzYT/q9AacwTzDpNbxILUT+TlBq6MY= +github.com/onsi/gomega v1.27.0 h1:QLidEla4bXUuZVFa4KX6JHCsuGgbi85LC/pCHrt/O08= +github.com/onsi/gomega v1.27.0/go.mod h1:i189pavgK95OSIipFBa74gC2V4qrQuvjuyGEr3GmbXA= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= oras.land/oras-go/v2 v2.0.0 h1:+LRAz92WF7AvYQsQjPEAIw3Xb2zPPhuydjpi4pIHmc0= diff --git a/test/e2e/internal/testdata/foobar/const.go b/test/e2e/internal/testdata/foobar/const.go index 7e172dda0..865f97300 100644 --- a/test/e2e/internal/testdata/foobar/const.go +++ b/test/e2e/internal/testdata/foobar/const.go @@ -15,7 +15,11 @@ limitations under the License. package foobar -import "oras.land/oras/test/e2e/internal/utils/match" +import ( + "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "oras.land/oras/test/e2e/internal/utils/match" +) var ( Tag = "foobar" @@ -63,11 +67,35 @@ func ImageConfigStateKey(configName string) match.StateKey { // referrers var ( - SBOMImageReferrerDigest = "sha256:32b78bd00723cd7d5251d4586f84d252530b7b5fe1c4104532767e6da4e04e47" - SignatureImageReferrerDigest = "sha256:0e007dcb9ded7f49c4dc8e3eed4a446712eb6fdf08a665a4f2352d6d2f8bdf17" - SBOMArtifactReferrerDigest = "sha256:8d7a27ff2662dae183f762d281f46d626ba7b6e56a72cc9959cdbcd91aad7fbc" - SignatureArtifactReferrerDigest = "sha256:0e007dcb9ded7f49c4dc8e3eed4a446712eb6fdf08a665a4f2352d6d2f8bdf17" - ArtifactReferrerStateKeys = []match.StateKey{ + SBOMImageReferrer = ocispec.Descriptor{ + MediaType: "application/vnd.oci.image.manifest.v1+json", + Digest: digest.Digest("sha256:32b78bd00723cd7d5251d4586f84d252530b7b5fe1c4104532767e6da4e04e47"), + Size: 660, + Annotations: map[string]string{ + "org.opencontainers.image.created": "2023-01-18T08:37:42Z", + }, + ArtifactType: "test.sbom.file", + } + SignatureImageReferrer = ocispec.Descriptor{ + MediaType: "application/vnd.oci.image.manifest.v1+json", + Digest: digest.Digest("sha256:0e007dcb9ded7f49c4dc8e3eed4a446712eb6fdf08a665a4f2352d6d2f8bdf17"), + Size: 670, + } + SBOMArtifactReferrer = ocispec.Descriptor{ + MediaType: "application/vnd.oci.artifact.manifest.v1+json", + Digest: digest.Digest("sha256:8d7a27ff2662dae183f762d281f46d626ba7b6e56a72cc9959cdbcd91aad7fbc"), + Size: 547, + Annotations: map[string]string{ + "org.opencontainers.artifact.created": "2023-01-16T05:49:46Z", + }, + ArtifactType: "test.sbom.file", + } + SignatureArtifactReferrer = ocispec.Descriptor{ + MediaType: "application/vnd.oci.artifact.manifest.v1+json", + Digest: digest.Digest("sha256:2dbea575a3490375f5052fbeb380a2f498866d99eb809b4168e49e224a274a39"), + Size: 560, + } + ArtifactReferrerStateKeys = []match.StateKey{ {Digest: "8d7a27ff2662", Name: "application/vnd.oci.artifact.manifest.v1+json"}, {Digest: "2dbea575a349", Name: "application/vnd.oci.artifact.manifest.v1+json"}, } @@ -87,6 +115,19 @@ var ( // fallback referrers var ( - FallbackSignatureImageReferrerDigest = "sha256:8b3f7e000c4a6d32cd6bfcabfe874ed470d470501a09adc65afaf1c342f988ff" - FallbackSBOMImageReferrerDigest = "sha256:316405db72cc8f0212c19db23b498f9af8a456c9cd288f9e33acd1ba9e7cd534" + FallbackSignatureImageReferrer = ocispec.Descriptor{ + MediaType: "application/vnd.oci.image.manifest.v1+json", + Digest: digest.Digest("sha256:8b3f7e000c4a6d32cd6bfcabfe874ed470d470501a09adc65afaf1c342f988ff"), + Size: 670, + } + + FallbackSBOMImageReferrer = ocispec.Descriptor{ + MediaType: "application/vnd.oci.image.manifest.v1+json", + Digest: digest.Digest("sha256:316405db72cc8f0212c19db23b498f9af8a456c9cd288f9e33acd1ba9e7cd534"), + Size: 660, + Annotations: map[string]string{ + "org.opencontainers.image.created": "2023-01-29T02:32:18Z", + }, + ArtifactType: "test.sbom.file", + } ) diff --git a/test/e2e/internal/testdata/multi_arch/const.go b/test/e2e/internal/testdata/multi_arch/const.go index 408036dbb..34d5cfb2f 100644 --- a/test/e2e/internal/testdata/multi_arch/const.go +++ b/test/e2e/internal/testdata/multi_arch/const.go @@ -16,6 +16,7 @@ limitations under the License. package multi_arch import ( + "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "oras.land/oras/test/e2e/internal/utils/match" ) @@ -35,13 +36,26 @@ var ( // child images var ( - LinuxAMD64Manifest = `{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","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"}}]}` - LinuxAMD64Digest = "sha256:9d84a5716c66a1d1b9c13f8ed157ba7d1edfe7f9b8766728b8a1f25c0d9c14c1" - LinuxAMD64Desc = `{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:9d84a5716c66a1d1b9c13f8ed157ba7d1edfe7f9b8766728b8a1f25c0d9c14c1","size":458}` - LinuxAMD64IndexDesc = `{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:9d84a5716c66a1d1b9c13f8ed157ba7d1edfe7f9b8766728b8a1f25c0d9c14c1","size":458,"platform":{"architecture":"amd64","os":"linux"}}` - LinuxAMD64Config = "{\r\n \"architecture\": \"amd64\",\r\n \"os\": \"linux\"\r\n}" - LinuxAMD64ConfigDesc = `{"mediaType":"application/vnd.oci.image.config.v1+json","digest":"sha256:fe9dbc99451d0517d65e048c309f0b5afb2cc513b7a3d456b6cc29fe641386c5","size":53}` - LinuxAMD64ReferrerDigest = "sha256:57e6462826c85be15f22f824666f6b467d488fa7bc7e2975f43a2fae27a24ef0" + LinuxAMD64Manifest = `{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","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"}}]}` + LinuxAMD64 = ocispec.Descriptor{ + MediaType: "application/vnd.oci.image.manifest.v1+json", + Digest: digest.Digest("sha256:9d84a5716c66a1d1b9c13f8ed157ba7d1edfe7f9b8766728b8a1f25c0d9c14c1"), + Size: 458, + } + LinuxAMD64DescStr = `{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:9d84a5716c66a1d1b9c13f8ed157ba7d1edfe7f9b8766728b8a1f25c0d9c14c1","size":458}` + LinuxAMD64IndexDesc = `{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:9d84a5716c66a1d1b9c13f8ed157ba7d1edfe7f9b8766728b8a1f25c0d9c14c1","size":458,"platform":{"architecture":"amd64","os":"linux"}}` + LinuxAMD64Config = "{\r\n \"architecture\": \"amd64\",\r\n \"os\": \"linux\"\r\n}" + LinuxAMD64ConfigDesc = `{"mediaType":"application/vnd.oci.image.config.v1+json","digest":"sha256:fe9dbc99451d0517d65e048c309f0b5afb2cc513b7a3d456b6cc29fe641386c5","size":53}` + LinuxAMD64Referrer = ocispec.Descriptor{ + MediaType: "application/vnd.oci.image.manifest.v1+json", + Digest: digest.Digest("sha256:57e6462826c85be15f22f824666f6b467d488fa7bc7e2975f43a2fae27a24ef0"), + Annotations: map[string]string{ + "org.opencontainers.image.created": "2023-02-15T07:56:34Z", + "subject": "linux/amd64", + }, + ArtifactType: "referrer.image", + Size: 481, + } LayerName = "hello.tar" LinuxAMD64ReferrerStateKey = match.StateKey{Digest: "57e6462826c8", Name: "application/vnd.oci.image.manifest.v1+json"} LinuxAMD64ReferrerConfigStateKey = match.StateKey{Digest: "44136fa355b3", Name: "referrer.image"} diff --git a/test/e2e/suite/command/cp.go b/test/e2e/suite/command/cp.go index 17e842baa..d5f8d734b 100644 --- a/test/e2e/suite/command/cp.go +++ b/test/e2e/suite/command/cp.go @@ -112,7 +112,7 @@ var _ = Describe("Common registry users:", func() { Expect(json.Unmarshal(bytes, &index)).ShouldNot(HaveOccurred()) Expect(len(index.Manifests)).To(Equal(1)) Expect(index.Manifests[0].Digest.String()).To(Equal(ma.IndexReferrerDigest)) - ORAS("manifest", "fetch", Reference(Host, dstRepo, ma.LinuxAMD64ReferrerDigest)). + ORAS("manifest", "fetch", Reference(Host, dstRepo, ma.LinuxAMD64Referrer.Digest.String())). WithDescription("not copy referrer of successor"). ExpectFailure(). Exec() @@ -136,7 +136,7 @@ var _ = Describe("Common registry users:", func() { Expect(json.Unmarshal(bytes, &index)).ShouldNot(HaveOccurred()) Expect(len(index.Manifests)).To(Equal(1)) Expect(index.Manifests[0].Digest.String()).To(Equal(ma.IndexReferrerDigest)) - ORAS("manifest", "fetch", Reference(Host, dstRepo, ma.LinuxAMD64ReferrerDigest)). + ORAS("manifest", "fetch", Reference(Host, dstRepo, ma.LinuxAMD64Referrer.Digest.String())). WithDescription("not copy referrer of successor"). ExpectFailure(). Exec() @@ -148,9 +148,9 @@ var _ = Describe("Common registry users:", func() { ORAS("cp", src, dst, "--platform", "linux/amd64", "-v"). MatchStatus(ma.IndexStateKeys, true, len(ma.IndexStateKeys)). - MatchKeyWords("Digest: " + ma.LinuxAMD64Digest). + MatchKeyWords("Digest: " + ma.LinuxAMD64.Digest.String()). Exec() - validate(Reference(Host, ImageRepo, ma.LinuxAMD64Digest), dst) + validate(Reference(Host, ImageRepo, ma.LinuxAMD64.Digest.String()), dst) }) It("should copy a certain platform of image to a new repository via digest", func() { @@ -159,9 +159,9 @@ var _ = Describe("Common registry users:", func() { dst := Reference(Host, dstRepo, "") ORAS("cp", src, dst, "--platform", "linux/amd64", "-v"). MatchStatus(ma.IndexStateKeys, true, len(ma.IndexStateKeys)). - MatchKeyWords("Digest: " + ma.LinuxAMD64Digest). + MatchKeyWords("Digest: " + ma.LinuxAMD64.Digest.String()). Exec() - validate(Reference(Host, ImageRepo, ma.LinuxAMD64Digest), Reference(Host, dstRepo, ma.LinuxAMD64Digest)) + validate(Reference(Host, ImageRepo, ma.LinuxAMD64.Digest.String()), Reference(Host, dstRepo, ma.LinuxAMD64.Digest.String())) }) It("should copy a certain platform of image and its referrers to a new repository with tag", func() { @@ -170,18 +170,18 @@ var _ = Describe("Common registry users:", func() { dst := Reference(Host, dstRepo, "copiedTag") ORAS("cp", src, dst, "-r", "--platform", "linux/amd64", "-v"). MatchStatus(ma.IndexStateKeys, true, len(ma.IndexStateKeys)). - MatchKeyWords("Digest: " + ma.LinuxAMD64Digest). + MatchKeyWords("Digest: " + ma.LinuxAMD64.Digest.String()). Exec() // validate - validate(Reference(Host, ImageRepo, ma.LinuxAMD64Digest), dst) + validate(Reference(Host, ImageRepo, ma.LinuxAMD64.Digest.String()), dst) var index ocispec.Index bytes := ORAS("discover", dst, "-o", "json", "--platform", "linux/amd64"). - MatchKeyWords(ma.LinuxAMD64ReferrerDigest). + MatchKeyWords(ma.LinuxAMD64Referrer.Digest.String()). WithDescription("discover amd64 referrers"). Exec().Out.Contents() Expect(json.Unmarshal(bytes, &index)).ShouldNot(HaveOccurred()) Expect(len(index.Manifests)).To(Equal(1)) - Expect(index.Manifests[0].Digest.String()).To(Equal(ma.LinuxAMD64ReferrerDigest)) + Expect(index.Manifests[0].Digest.String()).To(Equal(ma.LinuxAMD64Referrer.Digest.String())) ORAS("manifest", "fetch", Reference(Host, dstRepo, ma.Digest)). WithDescription("not copy index"). ExpectFailure(). @@ -197,19 +197,19 @@ var _ = Describe("Common registry users:", func() { dstRepo := cpTestRepo("platform-referrers-no-tag") ORAS("cp", src, Reference(Host, dstRepo, ""), "-r", "--platform", "linux/amd64", "-v"). MatchStatus(ma.IndexStateKeys, true, len(ma.IndexStateKeys)). - MatchKeyWords("Digest: " + ma.LinuxAMD64Digest). + MatchKeyWords("Digest: " + ma.LinuxAMD64.Digest.String()). Exec() // validate - dstRef := Reference(Host, dstRepo, ma.LinuxAMD64Digest) - validate(Reference(Host, ImageRepo, ma.LinuxAMD64Digest), dstRef) + dstRef := Reference(Host, dstRepo, ma.LinuxAMD64.Digest.String()) + validate(Reference(Host, ImageRepo, ma.LinuxAMD64.Digest.String()), dstRef) var index ocispec.Index bytes := ORAS("discover", dstRef, "-o", "json", "--platform", "linux/amd64"). - MatchKeyWords(ma.LinuxAMD64ReferrerDigest). + MatchKeyWords(ma.LinuxAMD64Referrer.Digest.String()). WithDescription("discover amd64 referrers"). Exec().Out.Contents() Expect(json.Unmarshal(bytes, &index)).ShouldNot(HaveOccurred()) Expect(len(index.Manifests)).To(Equal(1)) - Expect(index.Manifests[0].Digest.String()).To(Equal(ma.LinuxAMD64ReferrerDigest)) + Expect(index.Manifests[0].Digest.String()).To(Equal(ma.LinuxAMD64Referrer.Digest.String())) ORAS("manifest", "fetch", Reference(Host, dstRepo, ma.Digest)). WithDescription("not copy index"). ExpectFailure(). @@ -244,22 +244,22 @@ var _ = Describe("OCI spec 1.0 registry users:", func() { It("should copy an image artifact and its referrers from a registry to a fallback registry", func() { repo := cpTestRepo("to-fallback") stateKeys := append(append(foobarStates, foobar.ImageReferrersStateKeys...), foobar.ImageReferrerConfigStateKeys...) - src := Reference(Host, ArtifactRepo, foobar.SignatureImageReferrerDigest) + src := Reference(Host, ArtifactRepo, foobar.SignatureImageReferrer.Digest.String()) dst := Reference(FallbackHost, repo, "") ORAS("cp", "-r", src, dst, "-v").MatchStatus(stateKeys, true, len(stateKeys)).Exec() - validate(src, Reference(FallbackHost, repo, foobar.SignatureImageReferrerDigest)) + validate(src, Reference(FallbackHost, repo, foobar.SignatureImageReferrer.Digest.String())) ORAS("discover", "-o", "tree", Reference(FallbackHost, repo, foobar.Digest)). - WithDescription("discover referrer via subject").MatchKeyWords(foobar.SignatureImageReferrerDigest, foobar.SBOMImageReferrerDigest).Exec() + WithDescription("discover referrer via subject").MatchKeyWords(foobar.SignatureImageReferrer.Digest.String(), foobar.SBOMImageReferrer.Digest.String()).Exec() }) It("should copy an image artifact and its referrers from a fallback registry to a registry", func() { repo := cpTestRepo("from-fallback") stateKeys := append(append(foobarStates, foobar.FallbackImageReferrersStateKeys...), foobar.ImageReferrerConfigStateKeys...) - src := Reference(FallbackHost, ArtifactRepo, foobar.FallbackSBOMImageReferrerDigest) + src := Reference(FallbackHost, ArtifactRepo, foobar.FallbackSBOMImageReferrer.Digest.String()) dst := Reference(Host, repo, "") ORAS("cp", "-r", src, dst, "-v").MatchStatus(stateKeys, true, len(stateKeys)).Exec() - validate(src, Reference(Host, repo, foobar.FallbackSBOMImageReferrerDigest)) + validate(src, Reference(Host, repo, foobar.FallbackSBOMImageReferrer.Digest.String())) ORAS("discover", "-o", "tree", Reference(Host, repo, foobar.Digest)). - WithDescription("discover referrer via subject").MatchKeyWords(foobar.FallbackSignatureImageReferrerDigest, foobar.FallbackSBOMImageReferrerDigest).Exec() + WithDescription("discover referrer via subject").MatchKeyWords(foobar.FallbackSignatureImageReferrer.Digest.String(), foobar.FallbackSBOMImageReferrer.Digest.String()).Exec() }) }) }) diff --git a/test/e2e/suite/command/discover.go b/test/e2e/suite/command/discover.go new file mode 100644 index 000000000..39cbee383 --- /dev/null +++ b/test/e2e/suite/command/discover.go @@ -0,0 +1,175 @@ +/* +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" + "strings" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "gopkg.in/yaml.v2" + "oras.land/oras/test/e2e/internal/testdata/foobar" + "oras.land/oras/test/e2e/internal/testdata/multi_arch" + . "oras.land/oras/test/e2e/internal/utils" +) + +func discoverKeyWords(verbose bool, descs ...ocispec.Descriptor) []string { + var ret []string + for _, d := range descs { + ret = append(ret, d.Digest.String(), d.ArtifactType) + if verbose { + for k, v := range d.Annotations { + bytes, err := yaml.Marshal(map[string]string{k: v}) + Expect(err).ShouldNot(HaveOccurred()) + ret = append(ret, strings.TrimSpace(string(bytes))) + } + } + } + return ret +} + +var _ = Describe("ORAS beginners:", func() { + When("running discover command", func() { + RunAndShowPreviewInHelp([]string{"discover"}) + + It("should show preview and help doc", func() { + ORAS("discover", "--help").MatchKeyWords("[Preview] Discover", PreviewDesc, ExampleDesc).Exec() + }) + + It("should fail when no subject reference provided", func() { + ORAS("discover").ExpectFailure().MatchErrKeyWords("Error:").Exec() + }) + + It("should fail when no tag or digest found in provided subject reference", func() { + ORAS("discover", Reference(Host, Repo, "")).ExpectFailure().MatchErrKeyWords("Error:", "invalid image reference").Exec() + }) + }) +}) + +var _ = Describe("Common registry users:", func() { + subjectRef := Reference(Host, ArtifactRepo, foobar.Tag) + When("running discover command with json output", func() { + format := "json" + It("should discover direct referrers of a subject", func() { + bytes := ORAS("discover", subjectRef, "-o", format).Exec().Out.Contents() + var index ocispec.Index + Expect(json.Unmarshal(bytes, &index)).ShouldNot(HaveOccurred()) + Expect(index.Manifests).To(HaveLen(2)) + Expect(index.Manifests).Should(ContainElement(foobar.SBOMImageReferrer)) + Expect(index.Manifests).Should(ContainElement(foobar.SBOMArtifactReferrer)) + }) + + It("should discover matched referrer when filtering", func() { + bytes := ORAS("discover", subjectRef, "-o", format, "--artifact-type", foobar.SBOMArtifactReferrer.ArtifactType).Exec().Out.Contents() + var index ocispec.Index + Expect(json.Unmarshal(bytes, &index)).ShouldNot(HaveOccurred()) + Expect(index.Manifests).To(HaveLen(2)) + Expect(index.Manifests).Should(ContainElement(foobar.SBOMImageReferrer)) + Expect(index.Manifests).Should(ContainElement(foobar.SBOMArtifactReferrer)) + }) + + It("should discover matched no referrer", func() { + bytes := ORAS("discover", subjectRef, "-o", format, "--artifact-type", "???").Exec().Out.Contents() + var index ocispec.Index + Expect(json.Unmarshal(bytes, &index)).ShouldNot(HaveOccurred()) + Expect(index.Manifests).To(HaveLen(0)) + }) + + It("should discover one referrer with matched platform", func() { + bytes := ORAS("discover", Reference(Host, ArtifactRepo, multi_arch.Tag), "-o", format, "--platform", "linux/amd64").Exec().Out.Contents() + var index ocispec.Index + Expect(json.Unmarshal(bytes, &index)).ShouldNot(HaveOccurred()) + Expect(index.Manifests).To(HaveLen(1)) + Expect(index.Manifests).Should(ContainElement(multi_arch.LinuxAMD64Referrer)) + }) + }) + + When("running discover command with tree output", func() { + format := "tree" + referrers := []ocispec.Descriptor{foobar.SBOMImageReferrer, foobar.SBOMArtifactReferrer, foobar.SignatureImageReferrer, foobar.SignatureArtifactReferrer} + It("should discover all referrers of a subject", func() { + ORAS("discover", subjectRef, "-o", format). + MatchKeyWords(append(discoverKeyWords(false, referrers...), Reference(Host, ArtifactRepo, foobar.Digest))...). + Exec() + }) + + It("should discover all referrers of a subject with annotations", func() { + ORAS("discover", subjectRef, "-o", format, "-v"). + MatchKeyWords(append(discoverKeyWords(true, referrers...), Reference(Host, ArtifactRepo, foobar.Digest))...). + Exec() + + }) + }) + When("running discover command with table output", func() { + format := "table" + It("should all referrers of a subject", func() { + referrers := []ocispec.Descriptor{foobar.SBOMImageReferrer, foobar.SBOMArtifactReferrer} + ORAS("discover", subjectRef, "-o", format). + MatchKeyWords(append(discoverKeyWords(false, referrers...), foobar.Digest)...). + Exec() + }) + }) +}) + +var _ = Describe("Fallback registry users:", func() { + subjectRef := Reference(FallbackHost, ArtifactRepo, foobar.Tag) + When("running discover command", func() { + It("should discover direct referrers of a subject via json output", func() { + bytes := ORAS("discover", subjectRef, "-o", "json").Exec().Out.Contents() + var index ocispec.Index + Expect(json.Unmarshal(bytes, &index)).ShouldNot(HaveOccurred()) + Expect(index.Manifests).To(HaveLen(1)) + Expect(index.Manifests).Should(ContainElement(foobar.FallbackSBOMImageReferrer)) + }) + + It("should discover matched referrer when filtering via json output", func() { + bytes := ORAS("discover", subjectRef, "-o", "json", "--artifact-type", foobar.FallbackSBOMImageReferrer.ArtifactType).Exec().Out.Contents() + var index ocispec.Index + Expect(json.Unmarshal(bytes, &index)).ShouldNot(HaveOccurred()) + Expect(index.Manifests).To(HaveLen(1)) + Expect(index.Manifests).Should(ContainElement(foobar.FallbackSBOMImageReferrer)) + }) + + It("should discover no referrer when not matching via json output", func() { + bytes := ORAS("discover", subjectRef, "-o", "json", "--artifact-type", "???").Exec().Out.Contents() + var index ocispec.Index + Expect(json.Unmarshal(bytes, &index)).ShouldNot(HaveOccurred()) + Expect(index.Manifests).To(HaveLen(0)) + }) + + It("should discover all referrers of a subject via tree output", func() { + referrers := []ocispec.Descriptor{foobar.FallbackSBOMImageReferrer, foobar.FallbackSignatureImageReferrer} + ORAS("discover", subjectRef, "-o", "tree"). + MatchKeyWords(append(discoverKeyWords(false, referrers...), Reference(FallbackHost, ArtifactRepo, foobar.Digest))...). + Exec() + }) + + It("should discover all referrers with annotation via tree output", func() { + referrers := []ocispec.Descriptor{foobar.FallbackSBOMImageReferrer, foobar.FallbackSignatureImageReferrer} + ORAS("discover", subjectRef, "-o", "tree", "-v"). + MatchKeyWords(append(discoverKeyWords(true, referrers...), Reference(FallbackHost, ArtifactRepo, foobar.Digest))...). + Exec() + }) + It("should all referrers of a subject via table output", func() { + referrers := []ocispec.Descriptor{foobar.FallbackSBOMImageReferrer} + ORAS("discover", subjectRef, "-o", "table"). + MatchKeyWords(append(discoverKeyWords(false, referrers...), foobar.Digest)...). + Exec() + }) + }) +}) diff --git a/test/e2e/suite/command/manifest.go b/test/e2e/suite/command/manifest.go index 910a0760b..cf5a5f2d9 100644 --- a/test/e2e/suite/command/manifest.go +++ b/test/e2e/suite/command/manifest.go @@ -179,7 +179,7 @@ var _ = Describe("Common registry users:", func() { }) It("should fetch manifest with platform validation", func() { - ORAS("manifest", "fetch", Reference(Host, ImageRepo, multi_arch.LinuxAMD64Digest), "--platform", "linux/amd64"). + ORAS("manifest", "fetch", Reference(Host, ImageRepo, multi_arch.LinuxAMD64.Digest.String()), "--platform", "linux/amd64"). MatchContent(multi_arch.LinuxAMD64Manifest).Exec() }) @@ -194,8 +194,8 @@ var _ = Describe("Common registry users:", func() { }) It("should fetch descriptor via digest with platform validation", func() { - ORAS("manifest", "fetch", Reference(Host, ImageRepo, multi_arch.LinuxAMD64Digest), "--platform", "linux/amd64", "--descriptor"). - MatchContent(multi_arch.LinuxAMD64Desc).Exec() + ORAS("manifest", "fetch", Reference(Host, ImageRepo, multi_arch.LinuxAMD64.Digest.String()), "--platform", "linux/amd64", "--descriptor"). + MatchContent(multi_arch.LinuxAMD64DescStr).Exec() }) It("should fetch descriptor via tag", func() { @@ -233,19 +233,19 @@ var _ = Describe("Common registry users:", func() { }) It("should fetch image content with media type assertion and platform validation", func() { - ORAS("manifest", "fetch", Reference(Host, ImageRepo, multi_arch.LinuxAMD64Digest), "--platform", "linux/amd64", "--media-type", "application/vnd.oci.image.manifest.v1+json"). + ORAS("manifest", "fetch", Reference(Host, ImageRepo, multi_arch.LinuxAMD64.Digest.String()), "--platform", "linux/amd64", "--media-type", "application/vnd.oci.image.manifest.v1+json"). MatchContent(multi_arch.LinuxAMD64Manifest).Exec() }) It("should fetch image descriptor with media type assertion and platform validation", func() { - ORAS("manifest", "fetch", Reference(Host, ImageRepo, multi_arch.LinuxAMD64Digest), "--platform", "linux/amd64", "--media-type", "application/vnd.oci.image.manifest.v1+json", "--descriptor"). - MatchContent(multi_arch.LinuxAMD64Desc).Exec() + ORAS("manifest", "fetch", Reference(Host, ImageRepo, multi_arch.LinuxAMD64.Digest.String()), "--platform", "linux/amd64", "--media-type", "application/vnd.oci.image.manifest.v1+json", "--descriptor"). + MatchContent(multi_arch.LinuxAMD64DescStr).Exec() }) It("should fail to fetch image if media type assertion fails", func() { - ORAS("manifest", "fetch", Reference(Host, ImageRepo, multi_arch.LinuxAMD64Digest), "--media-type", "this.will.not.be.found"). + ORAS("manifest", "fetch", Reference(Host, ImageRepo, multi_arch.LinuxAMD64.Digest.String()), "--media-type", "this.will.not.be.found"). ExpectFailure(). - MatchErrKeyWords(multi_arch.LinuxAMD64Digest, "error: ", "not found").Exec() + MatchErrKeyWords(multi_arch.LinuxAMD64.Digest.String(), "error: ", "not found").Exec() }) })