Skip to content

Commit

Permalink
conformance: initial commit for refererrers test
Browse files Browse the repository at this point in the history
  • Loading branch information
rchincha committed Jun 16, 2023
1 parent 58a1fe9 commit e586e62
Show file tree
Hide file tree
Showing 6 changed files with 563 additions and 40 deletions.
1 change: 1 addition & 0 deletions conformance/00_conformance_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ func TestConformance(t *testing.T) {
test02Push()
test03ContentDiscovery()
test04ContentManagement()
test05Referrers()
})

RegisterFailHandler(g.Fail)
Expand Down
334 changes: 334 additions & 0 deletions conformance/05_referrers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,334 @@
package conformance

import (
"encoding/json"
"fmt"
"net/http"

"github.com/bloodorangeio/reggie"
g "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
godigest "github.com/opencontainers/go-digest"
)

var test05Referrers = func() {
g.Context(titleReferrers, func() {

g.Context("Setup", func() {
g.Specify("Populate registry with empty JSON blob", func() {
SkipIfDisabled(referrers)
RunOnlyIf(runReferencesSetup)
// validate expected empty JSON blob digest
Expect(emptyJSONDescriptor.Digest).To(Equal(godigest.Digest("sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a")))
req := client.NewRequest(reggie.POST, "/v2/<name>/blobs/uploads/")
resp, err := client.Do(req)
Expect(err).To(BeNil())
req = client.NewRequest(reggie.PUT, resp.GetRelativeLocation()).
SetQueryParam("digest", emptyJSONDescriptor.Digest.String()).
SetHeader("Content-Type", "application/octet-stream").
SetHeader("Content-Length", fmt.Sprintf("%d", emptyJSONDescriptor.Size)).
SetBody(emptyJSONBlob)
resp, err = client.Do(req)
Expect(err).To(BeNil())
Expect(resp.StatusCode()).To(SatisfyAll(
BeNumerically(">=", 200),
BeNumerically("<", 300)))
})

g.Specify("Populate registry with reference blob before the image manifest is pushed", func() {
SkipIfDisabled(referrers)
RunOnlyIf(runReferencesSetup)
req := client.NewRequest(reggie.POST, "/v2/<name>/blobs/uploads/")
resp, err := client.Do(req)
Expect(err).To(BeNil())
req = client.NewRequest(reggie.PUT, resp.GetRelativeLocation()).
SetQueryParam("digest", testRefBlobADigest).
SetHeader("Content-Type", "application/octet-stream").
SetHeader("Content-Length", testRefBlobALength).
SetBody(testRefBlobA)
resp, err = client.Do(req)
Expect(err).To(BeNil())
Expect(resp.StatusCode()).To(SatisfyAll(
BeNumerically(">=", 200),
BeNumerically("<", 300)))
})

g.Specify("Populate registry with test references manifest (config.MediaType = artifactType)", func() {
SkipIfDisabled(referrers)
RunOnlyIf(runReferencesSetup)
req := client.NewRequest(reggie.PUT, "/v2/<name>/manifests/<reference>",
reggie.WithReference(refsManifestAConfigArtifactDigest)).
SetHeader("Content-Type", "application/vnd.oci.image.manifest.v1+json").
SetBody(refsManifestAConfigArtifactContent)
resp, err := client.Do(req)
Expect(err).To(BeNil())
Expect(resp.StatusCode()).To(SatisfyAll(
BeNumerically(">=", 200),
BeNumerically("<", 300)))
Expect(resp.Header().Get("OCI-Subject")).To(Equal(manifests[4].Digest))
})

g.Specify("Populate registry with test references manifest (ArtifactType, config.MediaType = emptyJSON)", func() {
SkipIfDisabled(referrers)
RunOnlyIf(runReferencesSetup)
req := client.NewRequest(reggie.PUT, "/v2/<name>/manifests/<reference>",
reggie.WithReference(refsManifestALayerArtifactDigest)).
SetHeader("Content-Type", "application/vnd.oci.image.manifest.v1+json").
SetBody(refsManifestALayerArtifactContent)
resp, err := client.Do(req)
Expect(err).To(BeNil())
Expect(resp.StatusCode()).To(SatisfyAll(
BeNumerically(">=", 200),
BeNumerically("<", 300)))
Expect(resp.Header().Get("OCI-Subject")).To(Equal(manifests[4].Digest))
})

g.Specify("Populate registry with test blob", func() {
SkipIfDisabled(referrers)
RunOnlyIf(runReferencesSetup)
req := client.NewRequest(reggie.POST, "/v2/<name>/blobs/uploads/")
resp, err := client.Do(req)
Expect(err).To(BeNil())
req = client.NewRequest(reggie.PUT, resp.GetRelativeLocation()).
SetQueryParam("digest", configs[4].Digest).
SetHeader("Content-Type", "application/octet-stream").
SetHeader("Content-Length", configs[4].ContentLength).
SetBody(configs[4].Content)
resp, err = client.Do(req)
Expect(err).To(BeNil())
Expect(resp.StatusCode()).To(SatisfyAll(
BeNumerically(">=", 200),
BeNumerically("<", 300)))
})

g.Specify("Populate registry with test layer", func() {
SkipIfDisabled(referrers)
RunOnlyIf(runReferencesSetup)
req := client.NewRequest(reggie.POST, "/v2/<name>/blobs/uploads/")
resp, err := client.Do(req)
Expect(err).To(BeNil())
req = client.NewRequest(reggie.PUT, resp.GetRelativeLocation()).
SetQueryParam("digest", layerBlobDigest).
SetHeader("Content-Type", "application/octet-stream").
SetHeader("Content-Length", layerBlobContentLength).
SetBody(layerBlobData)
resp, err = client.Do(req)
Expect(err).To(BeNil())
Expect(resp.StatusCode()).To(SatisfyAll(
BeNumerically(">=", 200),
BeNumerically("<", 300)))
})

g.Specify("Populate registry with test manifest", func() {
SkipIfDisabled(referrers)
RunOnlyIf(runReferencesSetup)
tag := testTagName
req := client.NewRequest(reggie.PUT, "/v2/<name>/manifests/<reference>",
reggie.WithReference(tag)).
SetHeader("Content-Type", "application/vnd.oci.image.manifest.v1+json").
SetBody(manifests[4].Content)
resp, err := client.Do(req)
Expect(err).To(BeNil())
Expect(resp.StatusCode()).To(SatisfyAll(
BeNumerically(">=", 200),
BeNumerically("<", 300)))
})

g.Specify("Populate registry with reference blob after the image manifest is pushed", func() {
SkipIfDisabled(referrers)
RunOnlyIf(runReferencesSetup)
req := client.NewRequest(reggie.POST, "/v2/<name>/blobs/uploads/")
resp, err := client.Do(req)
Expect(err).To(BeNil())
req = client.NewRequest(reggie.PUT, resp.GetRelativeLocation()).
SetQueryParam("digest", testRefBlobBDigest).
SetHeader("Content-Type", "application/octet-stream").
SetHeader("Content-Length", testRefBlobBLength).
SetBody(testRefBlobB)
resp, err = client.Do(req)
Expect(err).To(BeNil())
Expect(resp.StatusCode()).To(SatisfyAll(
BeNumerically(">=", 200),
BeNumerically("<", 300)))
})

g.Specify("Populate registry with test references manifest (config.MediaType = artifactType)", func() {
SkipIfDisabled(referrers)
RunOnlyIf(runReferencesSetup)
req := client.NewRequest(reggie.PUT, "/v2/<name>/manifests/<reference>",
reggie.WithReference(refsManifestBConfigArtifactDigest)).
SetHeader("Content-Type", "application/vnd.oci.image.manifest.v1+json").
SetBody(refsManifestBConfigArtifactContent)
resp, err := client.Do(req)
Expect(err).To(BeNil())
Expect(resp.StatusCode()).To(SatisfyAll(
BeNumerically(">=", 200),
BeNumerically("<", 300)))
Expect(resp.Header().Get("OCI-Subject")).To(Equal(manifests[4].Digest))
})

g.Specify("Populate registry with test references manifest (ArtifactType, config.MediaType = emptyJSON)", func() {
SkipIfDisabled(referrers)
RunOnlyIf(runReferencesSetup)
req := client.NewRequest(reggie.PUT, "/v2/<name>/manifests/<reference>",
reggie.WithReference(refsManifestBLayerArtifactDigest)).
SetHeader("Content-Type", "application/vnd.oci.image.manifest.v1+json").
SetBody(refsManifestBLayerArtifactContent)
resp, err := client.Do(req)
Expect(err).To(BeNil())
Expect(resp.StatusCode()).To(SatisfyAll(
BeNumerically(">=", 200),
BeNumerically("<", 300)))
Expect(resp.Header().Get("OCI-Subject")).To(Equal(manifests[4].Digest))
})
})

g.Context("Get references", func() {
g.Specify("GET request to nonexistent blob should result in empty 200 response", func() {
SkipIfDisabled(referrers)
req := client.NewRequest(reggie.GET, "/v2/<name>/referrers/<digest>",
reggie.WithDigest(dummyDigest))
resp, err := client.Do(req)
Expect(err).To(BeNil())
Expect(resp.StatusCode()).To(Equal(http.StatusOK))

var index Index
err = json.Unmarshal(resp.Body(), &index)
Expect(err).To(BeNil())
Expect(len(index.Manifests)).To(BeZero())
})

g.Specify("GET request to existing blob should yield 200", func() {
SkipIfDisabled(referrers)
req := client.NewRequest(reggie.GET, "/v2/<name>/referrers/<digest>",
reggie.WithDigest(manifests[4].Digest))
resp, err := client.Do(req)
Expect(err).To(BeNil())
Expect(resp.StatusCode()).To(Equal(http.StatusOK))
if h := resp.Header().Get("Docker-Content-Digest"); h != "" {
Expect(h).To(Equal(configs[4].Digest))
}

var index Index
err = json.Unmarshal(resp.Body(), &index)
Expect(err).To(BeNil())
Expect(len(index.Manifests)).To(Equal(4))
Expect(index.Manifests[0].Digest).ToNot(Equal(index.Manifests[1].Digest))
})

g.Specify("GET request to existing blob with filter should yield 200", func() {
SkipIfDisabled(referrers)
req := client.NewRequest(reggie.GET, "/v2/<name>/referrers/<digest>",
reggie.WithDigest(manifests[4].Digest)).
SetQueryParam("artifactType", testRefArtifactTypeA)
resp, err := client.Do(req)
Expect(err).To(BeNil())
Expect(resp.StatusCode()).To(Equal(http.StatusOK))
if h := resp.Header().Get("Docker-Content-Digest"); h != "" {
Expect(h).To(Equal(configs[4].Digest))
}

var index Index
err = json.Unmarshal(resp.Body(), &index)
Expect(err).To(BeNil())

// also check resp header "OCI-Filters-Applied: artifactType" denoting that an artifactType filter was applied
if resp.Header().Get("OCI-Filters-Applied") != "" {
Expect(len(index.Manifests)).To(Equal(2))
Expect(resp.Header().Get("OCI-Filters-Applied")).To(Equal(testRefArtifactTypeA))
} else {
Expect(len(index.Manifests)).To(Equal(4))
Warn("filtering by artifact-type is not implemented")
}
})
})

g.Context("Teardown", func() {
deleteReq := func(req *reggie.Request) {
SkipIfDisabled(push)
RunOnlyIf(runReferencesSetup)
resp, err := client.Do(req)
Expect(err).To(BeNil())
Expect(resp.StatusCode()).To(SatisfyAny(
SatisfyAll(
BeNumerically(">=", 200),
BeNumerically("<", 300),
),
Equal(http.StatusMethodNotAllowed),
))
}

if deleteManifestBeforeBlobs {
g.Specify("Delete manifest created in setup", func() {
SkipIfDisabled(referrers)
RunOnlyIf(runReferencesSetup)
req := client.NewRequest(reggie.DELETE, "/v2/<name>/manifests/<reference>",
reggie.WithReference(refsManifestAConfigArtifactDigest))
deleteReq(req)
req = client.NewRequest(reggie.DELETE, "/v2/<name>/manifests/<reference>",
reggie.WithReference(refsManifestALayerArtifactDigest))
deleteReq(req)
req = client.NewRequest(reggie.DELETE, "/v2/<name>/manifests/<digest>", reggie.WithDigest(manifests[4].Digest))
deleteReq(req)
req = client.NewRequest(reggie.DELETE, "/v2/<name>/manifests/<reference>",
reggie.WithReference(refsManifestBConfigArtifactDigest))
deleteReq(req)
req = client.NewRequest(reggie.DELETE, "/v2/<name>/manifests/<reference>",
reggie.WithReference(refsManifestBLayerArtifactDigest))
deleteReq(req)
})
}

g.Specify("Delete config blob created in setup", func() {
SkipIfDisabled(referrers)
RunOnlyIf(runReferencesSetup)
req := client.NewRequest(reggie.DELETE, "/v2/<name>/blobs/<digest>", reggie.WithDigest(configs[4].Digest))
deleteReq(req)
})

g.Specify("Delete layer blob created in setup", func() {
SkipIfDisabled(referrers)
RunOnlyIf(runReferencesSetup)
req := client.NewRequest(reggie.DELETE, "/v2/<name>/blobs/<digest>", reggie.WithDigest(layerBlobDigest))
deleteReq(req)
})

g.Specify("Delete reference blob created in setup", func() {
SkipIfDisabled(referrers)
RunOnlyIf(runReferencesSetup)
req := client.NewRequest(reggie.DELETE, "/v2/<name>/blobs/<digest>", reggie.WithDigest(testRefBlobADigest))
deleteReq(req)
req = client.NewRequest(reggie.DELETE, "/v2/<name>/blobs/<digest>", reggie.WithDigest(testRefBlobBDigest))
deleteReq(req)
})

g.Specify("Delete empty JSON blob created in setup", func() {
SkipIfDisabled(referrers)
RunOnlyIf(runReferencesSetup)
req := client.NewRequest(reggie.DELETE, "/v2/<name>/blobs/<digest>", reggie.WithDigest(emptyJSONDescriptor.Digest.String()))
deleteReq(req)
})

if !deleteManifestBeforeBlobs {
g.Specify("Delete manifest created in setup", func() {
SkipIfDisabled(referrers)
RunOnlyIf(runReferencesSetup)
req := client.NewRequest(reggie.DELETE, "/v2/<name>/manifests/<reference>",
reggie.WithReference(refsManifestAConfigArtifactDigest))
deleteReq(req)
req = client.NewRequest(reggie.DELETE, "/v2/<name>/manifests/<reference>",
reggie.WithReference(refsManifestALayerArtifactDigest))
deleteReq(req)
req = client.NewRequest(reggie.DELETE, "/v2/<name>/manifests/<digest>", reggie.WithDigest(manifests[4].Digest))
deleteReq(req)
req = client.NewRequest(reggie.DELETE, "/v2/<name>/manifests/<reference>",
reggie.WithReference(refsManifestBConfigArtifactDigest))
deleteReq(req)
req = client.NewRequest(reggie.DELETE, "/v2/<name>/manifests/<reference>",
reggie.WithReference(refsManifestBLayerArtifactDigest))
deleteReq(req)
})
}
})
})
}
3 changes: 3 additions & 0 deletions conformance/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ require (

require (
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-resty/resty/v2 v2.7.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/nxadm/tail v1.4.8 // indirect
golang.org/x/net v0.8.0 // indirect
Expand Down
8 changes: 8 additions & 0 deletions conformance/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ github.com/bloodorangeio/reggie v0.6.1 h1:rSpfPN8oU9kflRI7aQVjImjhY5meRsXDIXnJQr
github.com/bloodorangeio/reggie v0.6.1/go.mod h1:Jkvg7UBdlXVNOlvXU6hgysdtG1XNVCB3B4/k7+PtlfM=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
Expand All @@ -28,6 +30,11 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
Expand Down Expand Up @@ -87,6 +94,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
Expand Down
Loading

0 comments on commit e586e62

Please sign in to comment.