mirror of
https://github.com/project-zot/zot.git
synced 2024-12-16 21:56:37 -05:00
Merge pull request #30 from rchincha/compliance
compliance: initial commit
This commit is contained in:
commit
51db55c890
10 changed files with 249 additions and 116 deletions
15
README.md
15
README.md
|
@ -1,8 +1,7 @@
|
||||||
# zot [![Build Status](https://travis-ci.org/anuvu/zot.svg?branch=master)](https://travis-ci.org/anuvu/zot) [![codecov.io](http://codecov.io/github/anuvu/zot/coverage.svg?branch=master)](http://codecov.io/github/anuvu/zot?branch=master)
|
# zot [![Build Status](https://travis-ci.org/anuvu/zot.svg?branch=master)](https://travis-ci.org/anuvu/zot) [![codecov.io](http://codecov.io/github/anuvu/zot/coverage.svg?branch=master)](http://codecov.io/github/anuvu/zot?branch=master)
|
||||||
|
|
||||||
**zot** is a vendor-neutral OCI image repository server purely based on
|
**zot** is a vendor-neutral OCI image repository server purely based on
|
||||||
[OCI Distribution Specification]
|
[OCI Distribution Specification](https://github.com/opencontainers/distribution-spec).
|
||||||
(https://github.com/opencontainers/distribution-spec).
|
|
||||||
|
|
||||||
* Conforms to [OCI distribution spec](https://github.com/opencontainers/distribution-spec) APIs
|
* Conforms to [OCI distribution spec](https://github.com/opencontainers/distribution-spec) APIs
|
||||||
* Uses [OCI storage layout](https://github.com/opencontainers/image-spec/blob/master/image-layout.md) for storage layout
|
* Uses [OCI storage layout](https://github.com/opencontainers/image-spec/blob/master/image-layout.md) for storage layout
|
||||||
|
@ -10,6 +9,7 @@
|
||||||
* Authentication via TLS mutual authentication and HTTP *BASIC* (local _htpasswd_ and LDAP)
|
* Authentication via TLS mutual authentication and HTTP *BASIC* (local _htpasswd_ and LDAP)
|
||||||
* Doesn't require _root_ privileges
|
* Doesn't require _root_ privileges
|
||||||
* Swagger based documentation
|
* Swagger based documentation
|
||||||
|
* Can run compliance checks against registries
|
||||||
* Released under Apache 2.0 License
|
* Released under Apache 2.0 License
|
||||||
|
|
||||||
# Presentations
|
# Presentations
|
||||||
|
@ -39,12 +39,19 @@ make
|
||||||
|
|
||||||
Build artifacts are in bin/
|
Build artifacts are in bin/
|
||||||
|
|
||||||
# Running
|
# Serving
|
||||||
|
```
|
||||||
bin/zot serve _config-file_
|
bin/zot serve _config-file_
|
||||||
|
```
|
||||||
|
|
||||||
Examples of config files are available in [examples/](examples/) dir.
|
Examples of config files are available in [examples/](examples/) dir.
|
||||||
|
|
||||||
|
# Compliance checks
|
||||||
|
|
||||||
|
```
|
||||||
|
bin/zot -H hostIP -P port [-V "all"]
|
||||||
|
```
|
||||||
|
|
||||||
# Ecosystem
|
# Ecosystem
|
||||||
|
|
||||||
## skopeo
|
## skopeo
|
||||||
|
|
|
@ -34,10 +34,7 @@ go_library(
|
||||||
go_test(
|
go_test(
|
||||||
name = "go_default_test",
|
name = "go_default_test",
|
||||||
timeout = "short",
|
timeout = "short",
|
||||||
srcs = [
|
srcs = ["controller_test.go"],
|
||||||
"controller_test.go",
|
|
||||||
"routes_test.go",
|
|
||||||
],
|
|
||||||
data = [
|
data = [
|
||||||
"//:exported_testdata",
|
"//:exported_testdata",
|
||||||
],
|
],
|
||||||
|
@ -45,8 +42,6 @@ go_test(
|
||||||
race = "on",
|
race = "on",
|
||||||
deps = [
|
deps = [
|
||||||
"@com_github_nmcclain_ldap//:go_default_library",
|
"@com_github_nmcclain_ldap//:go_default_library",
|
||||||
"@com_github_opencontainers_go_digest//:go_default_library",
|
|
||||||
"@com_github_opencontainers_image_spec//specs-go/v1:go_default_library",
|
|
||||||
"@com_github_smartystreets_goconvey//convey:go_default_library",
|
"@com_github_smartystreets_goconvey//convey:go_default_library",
|
||||||
"@in_gopkg_resty_v1//:go_default_library",
|
"@in_gopkg_resty_v1//:go_default_library",
|
||||||
],
|
],
|
||||||
|
|
|
@ -28,10 +28,13 @@ import (
|
||||||
httpSwagger "github.com/swaggo/http-swagger"
|
httpSwagger "github.com/swaggo/http-swagger"
|
||||||
)
|
)
|
||||||
|
|
||||||
const RoutePrefix = "/v2"
|
const (
|
||||||
const DistAPIVersion = "Docker-Distribution-API-Version"
|
RoutePrefix = "/v2"
|
||||||
const DistContentDigestKey = "Docker-Content-Digest"
|
DistAPIVersion = "Docker-Distribution-API-Version"
|
||||||
const BlobUploadUUID = "Blob-Upload-UUID"
|
DistContentDigestKey = "Docker-Content-Digest"
|
||||||
|
BlobUploadUUID = "Blob-Upload-UUID"
|
||||||
|
DefaultMediaType = "application/json"
|
||||||
|
)
|
||||||
|
|
||||||
type RouteHandler struct {
|
type RouteHandler struct {
|
||||||
c *Controller
|
c *Controller
|
||||||
|
@ -823,7 +826,7 @@ func WriteJSON(w http.ResponseWriter, status int, data interface{}) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
WriteData(w, status, "application/json; charset=utf-8", body)
|
WriteData(w, status, DefaultMediaType, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
func WriteData(w http.ResponseWriter, status int, mediaType string, data []byte) {
|
func WriteData(w http.ResponseWriter, status int, mediaType string, data []byte) {
|
||||||
|
|
|
@ -8,6 +8,8 @@ go_library(
|
||||||
deps = [
|
deps = [
|
||||||
"//errors:go_default_library",
|
"//errors:go_default_library",
|
||||||
"//pkg/api:go_default_library",
|
"//pkg/api:go_default_library",
|
||||||
|
"//pkg/compliance:go_default_library",
|
||||||
|
"//pkg/compliance/v1_0_0:go_default_library",
|
||||||
"//pkg/storage:go_default_library",
|
"//pkg/storage:go_default_library",
|
||||||
"@com_github_mitchellh_mapstructure//:go_default_library",
|
"@com_github_mitchellh_mapstructure//:go_default_library",
|
||||||
"@com_github_opencontainers_distribution_spec//:go_default_library",
|
"@com_github_opencontainers_distribution_spec//:go_default_library",
|
||||||
|
|
|
@ -1,14 +1,19 @@
|
||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/anuvu/zot/errors"
|
"github.com/anuvu/zot/errors"
|
||||||
"github.com/anuvu/zot/pkg/api"
|
"github.com/anuvu/zot/pkg/api"
|
||||||
|
"github.com/anuvu/zot/pkg/compliance"
|
||||||
"github.com/anuvu/zot/pkg/storage"
|
"github.com/anuvu/zot/pkg/storage"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
dspec "github.com/opencontainers/distribution-spec"
|
dspec "github.com/opencontainers/distribution-spec"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
|
"github.com/anuvu/zot/pkg/compliance/v1_0_0"
|
||||||
)
|
)
|
||||||
|
|
||||||
// metadataConfig reports metadata after parsing, which we use to track
|
// metadataConfig reports metadata after parsing, which we use to track
|
||||||
|
@ -23,6 +28,7 @@ func NewRootCmd() *cobra.Command {
|
||||||
showVersion := false
|
showVersion := false
|
||||||
config := api.NewConfig()
|
config := api.NewConfig()
|
||||||
|
|
||||||
|
// "serve"
|
||||||
serveCmd := &cobra.Command{
|
serveCmd := &cobra.Command{
|
||||||
Use: "serve <config>",
|
Use: "serve <config>",
|
||||||
Aliases: []string{"serve"},
|
Aliases: []string{"serve"},
|
||||||
|
@ -53,6 +59,7 @@ func NewRootCmd() *cobra.Command {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// "garbage-collect"
|
||||||
gcDelUntagged := false
|
gcDelUntagged := false
|
||||||
gcDryRun := false
|
gcDryRun := false
|
||||||
|
|
||||||
|
@ -79,6 +86,37 @@ func NewRootCmd() *cobra.Command {
|
||||||
gcCmd.Flags().BoolVarP(&gcDryRun, "dry-run", "d", false,
|
gcCmd.Flags().BoolVarP(&gcDryRun, "dry-run", "d", false,
|
||||||
"do everything except remove the blobs")
|
"do everything except remove the blobs")
|
||||||
|
|
||||||
|
// "compliance"
|
||||||
|
complianceConfig := compliance.NewConfig()
|
||||||
|
complianceCmd := &cobra.Command{
|
||||||
|
Use: "compliance",
|
||||||
|
Aliases: []string{"co"},
|
||||||
|
Short: "`compliance` checks compliance with respect to OCI distribution-spec",
|
||||||
|
Long: "`compliance` checks compliance with respect to OCI distribution-spec",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
t := &testing.T{}
|
||||||
|
switch complianceConfig.Version {
|
||||||
|
case "all":
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
v1_0_0.CheckWorkflows(t, complianceConfig)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
complianceCmd.Flags().StringVarP(&complianceConfig.Address, "address", "H", "",
|
||||||
|
"Registry server address")
|
||||||
|
if err := complianceCmd.MarkFlagRequired("address"); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
complianceCmd.Flags().StringVarP(&complianceConfig.Port, "port", "P", "",
|
||||||
|
"Registry server port")
|
||||||
|
if err := complianceCmd.MarkFlagRequired("port"); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
complianceCmd.Flags().StringVarP(&complianceConfig.Version, "version", "V", "all",
|
||||||
|
"OCI dist-spec version to check")
|
||||||
|
|
||||||
rootCmd := &cobra.Command{
|
rootCmd := &cobra.Command{
|
||||||
Use: "zot",
|
Use: "zot",
|
||||||
Short: "`zot`",
|
Short: "`zot`",
|
||||||
|
@ -93,6 +131,7 @@ func NewRootCmd() *cobra.Command {
|
||||||
|
|
||||||
rootCmd.AddCommand(serveCmd)
|
rootCmd.AddCommand(serveCmd)
|
||||||
rootCmd.AddCommand(gcCmd)
|
rootCmd.AddCommand(gcCmd)
|
||||||
|
rootCmd.AddCommand(complianceCmd)
|
||||||
rootCmd.Flags().BoolVarP(&showVersion, "version", "v", false, "show the version and exit")
|
rootCmd.Flags().BoolVarP(&showVersion, "version", "v", false, "show the version and exit")
|
||||||
|
|
||||||
return rootCmd
|
return rootCmd
|
||||||
|
|
8
pkg/compliance/BUILD.bazel
Normal file
8
pkg/compliance/BUILD.bazel
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = ["config.go"],
|
||||||
|
importpath = "github.com/anuvu/zot/pkg/compliance",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
11
pkg/compliance/config.go
Normal file
11
pkg/compliance/config.go
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package compliance
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Address string
|
||||||
|
Port string
|
||||||
|
Version string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConfig() *Config {
|
||||||
|
return &Config{}
|
||||||
|
}
|
28
pkg/compliance/v1_0_0/BUILD.bazel
Normal file
28
pkg/compliance/v1_0_0/BUILD.bazel
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = ["check.go"],
|
||||||
|
importpath = "github.com/anuvu/zot/pkg/compliance/v1_0_0",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [
|
||||||
|
"//pkg/api:go_default_library",
|
||||||
|
"//pkg/compliance:go_default_library",
|
||||||
|
"@com_github_opencontainers_go_digest//:go_default_library",
|
||||||
|
"@com_github_opencontainers_image_spec//specs-go/v1:go_default_library",
|
||||||
|
"@com_github_smartystreets_goconvey//convey:go_default_library",
|
||||||
|
"@in_gopkg_resty_v1//:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
go_test(
|
||||||
|
name = "go_default_test",
|
||||||
|
timeout = "short",
|
||||||
|
srcs = ["check_test.go"],
|
||||||
|
embed = [":go_default_library"],
|
||||||
|
deps = [
|
||||||
|
"//pkg/api:go_default_library",
|
||||||
|
"//pkg/compliance:go_default_library",
|
||||||
|
"@in_gopkg_resty_v1//:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
|
@ -1,96 +1,102 @@
|
||||||
// nolint (dupl)
|
//nolint (dupl)
|
||||||
package api_test
|
package v1_0_0
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/anuvu/zot/pkg/api"
|
"github.com/anuvu/zot/pkg/api"
|
||||||
|
"github.com/anuvu/zot/pkg/compliance"
|
||||||
godigest "github.com/opencontainers/go-digest"
|
godigest "github.com/opencontainers/go-digest"
|
||||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
"gopkg.in/resty.v1"
|
"gopkg.in/resty.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
func CheckWorkflows(t *testing.T, config *compliance.Config) {
|
||||||
DefaultContentType = "application/json; charset=utf-8"
|
if config == nil || config.Address == "" || config.Port == "" {
|
||||||
BaseURL = "http://127.0.0.1:8080"
|
panic("insufficient config")
|
||||||
)
|
}
|
||||||
|
baseURL := fmt.Sprintf("http://%s:%s", config.Address, config.Port)
|
||||||
|
|
||||||
|
fmt.Println("------------------------------")
|
||||||
|
fmt.Println("Checking for v1.0.0 compliance")
|
||||||
|
fmt.Println("------------------------------")
|
||||||
|
|
||||||
func TestAPI(t *testing.T) {
|
|
||||||
Convey("Make API calls to the controller", t, func(c C) {
|
Convey("Make API calls to the controller", t, func(c C) {
|
||||||
Convey("check version", func() {
|
Convey("Check version", func() {
|
||||||
resp, err := resty.R().Get(BaseURL + "/v2/")
|
Print("\nCheck version")
|
||||||
|
resp, err := resty.R().Get(baseURL + "/v2/")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 200)
|
So(resp.StatusCode(), ShouldEqual, 200)
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("Get repository catalog", func() {
|
Convey("Get repository catalog", func() {
|
||||||
resp, err := resty.R().Get(BaseURL + "/v2/_catalog")
|
Print("\nGet repository catalog")
|
||||||
|
resp, err := resty.R().Get(baseURL + "/v2/_catalog")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 200)
|
So(resp.StatusCode(), ShouldEqual, 200)
|
||||||
So(resp.String(), ShouldNotBeEmpty)
|
So(resp.String(), ShouldNotBeEmpty)
|
||||||
So(resp.Header().Get("Content-Type"), ShouldEqual, DefaultContentType)
|
So(resp.Header().Get("Content-Type"), ShouldEqual, api.DefaultMediaType)
|
||||||
var repoList api.RepositoryList
|
var repoList api.RepositoryList
|
||||||
err = json.Unmarshal(resp.Body(), &repoList)
|
err = json.Unmarshal(resp.Body(), &repoList)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(len(repoList.Repositories), ShouldEqual, 0)
|
So(len(repoList.Repositories), ShouldEqual, 0)
|
||||||
|
|
||||||
// after newly created upload should succeed
|
// after newly created upload should succeed
|
||||||
resp, err = resty.R().Post(BaseURL + "/v2/z/blobs/uploads/")
|
resp, err = resty.R().Post(baseURL + "/v2/z/blobs/uploads/")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 202)
|
So(resp.StatusCode(), ShouldEqual, 202)
|
||||||
|
|
||||||
// after newly created upload should succeed
|
// after newly created upload should succeed
|
||||||
resp, err = resty.R().Post(BaseURL + "/v2/a/b/c/d/blobs/uploads/")
|
resp, err = resty.R().Post(baseURL + "/v2/a/b/c/d/blobs/uploads/")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 202)
|
So(resp.StatusCode(), ShouldEqual, 202)
|
||||||
|
|
||||||
resp, err = resty.R().SetResult(&api.RepositoryList{}).Get(BaseURL + "/v2/_catalog")
|
resp, err = resty.R().SetResult(&api.RepositoryList{}).Get(baseURL + "/v2/_catalog")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 200)
|
So(resp.StatusCode(), ShouldEqual, 200)
|
||||||
So(resp.String(), ShouldNotBeEmpty)
|
So(resp.String(), ShouldNotBeEmpty)
|
||||||
r := resp.Result().(*api.RepositoryList)
|
r := resp.Result().(*api.RepositoryList)
|
||||||
|
So(len(r.Repositories), ShouldBeGreaterThan, 0)
|
||||||
So(r.Repositories[0], ShouldEqual, "a/b/c/d")
|
So(r.Repositories[0], ShouldEqual, "a/b/c/d")
|
||||||
So(r.Repositories[1], ShouldEqual, "z")
|
So(r.Repositories[1], ShouldEqual, "z")
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("Get images in a repository", func() {
|
Convey("Get images in a repository", func() {
|
||||||
|
Print("\nGet images in a repository")
|
||||||
// non-existent repository should fail
|
// non-existent repository should fail
|
||||||
resp, err := resty.R().Get(BaseURL + "/v2/repo/tags/list")
|
resp, err := resty.R().Get(baseURL + "/v2/repo/tags/list")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 404)
|
So(resp.StatusCode(), ShouldEqual, 404)
|
||||||
So(resp.String(), ShouldNotBeEmpty)
|
So(resp.String(), ShouldNotBeEmpty)
|
||||||
|
|
||||||
// after newly created upload should succeed
|
// after newly created upload should succeed
|
||||||
resp, err = resty.R().Post(BaseURL + "/v2/repo/blobs/uploads/")
|
resp, err = resty.R().Post(baseURL + "/v2/repo/blobs/uploads/")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 202)
|
So(resp.StatusCode(), ShouldEqual, 202)
|
||||||
|
|
||||||
resp, err = resty.R().Get(BaseURL + "/v2/repo/tags/list")
|
resp, err = resty.R().Get(baseURL + "/v2/repo/tags/list")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 200)
|
So(resp.StatusCode(), ShouldEqual, 200)
|
||||||
So(resp.String(), ShouldNotBeEmpty)
|
So(resp.String(), ShouldNotBeEmpty)
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("Monolithic blob upload", func() {
|
Convey("Monolithic blob upload", func() {
|
||||||
resp, err := resty.R().Post(BaseURL + "/v2/repo/blobs/uploads/")
|
Print("\nMonolithic blob upload")
|
||||||
|
resp, err := resty.R().Post(baseURL + "/v2/repo/blobs/uploads/")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 202)
|
So(resp.StatusCode(), ShouldEqual, 202)
|
||||||
loc := resp.Header().Get("Location")
|
loc := resp.Header().Get("Location")
|
||||||
So(loc, ShouldNotBeEmpty)
|
So(loc, ShouldNotBeEmpty)
|
||||||
|
|
||||||
resp, err = resty.R().Get(BaseURL + loc)
|
resp, err = resty.R().Get(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 204)
|
So(resp.StatusCode(), ShouldEqual, 204)
|
||||||
|
|
||||||
resp, err = resty.R().Get(BaseURL + "/v2/repo/tags/list")
|
resp, err = resty.R().Get(baseURL + "/v2/repo/tags/list")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 200)
|
So(resp.StatusCode(), ShouldEqual, 200)
|
||||||
So(resp.String(), ShouldNotBeEmpty)
|
So(resp.String(), ShouldNotBeEmpty)
|
||||||
|
@ -99,21 +105,21 @@ func TestAPI(t *testing.T) {
|
||||||
content := []byte("this is a blob")
|
content := []byte("this is a blob")
|
||||||
digest := godigest.FromBytes(content)
|
digest := godigest.FromBytes(content)
|
||||||
So(digest, ShouldNotBeNil)
|
So(digest, ShouldNotBeNil)
|
||||||
resp, err = resty.R().Put(BaseURL + loc)
|
resp, err = resty.R().Put(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 400)
|
So(resp.StatusCode(), ShouldEqual, 400)
|
||||||
// without the Content-Length should fail
|
// without the Content-Length should fail
|
||||||
resp, err = resty.R().SetQueryParam("digest", digest.String()).Put(BaseURL + loc)
|
resp, err = resty.R().SetQueryParam("digest", digest.String()).Put(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 400)
|
So(resp.StatusCode(), ShouldEqual, 400)
|
||||||
// without any data to send, should fail
|
// without any data to send, should fail
|
||||||
resp, err = resty.R().SetQueryParam("digest", digest.String()).
|
resp, err = resty.R().SetQueryParam("digest", digest.String()).
|
||||||
SetHeader("Content-Type", "application/octet-stream").Put(BaseURL + loc)
|
SetHeader("Content-Type", "application/octet-stream").Put(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 400)
|
So(resp.StatusCode(), ShouldEqual, 400)
|
||||||
// monolithic blob upload: success
|
// monolithic blob upload: success
|
||||||
resp, err = resty.R().SetQueryParam("digest", digest.String()).
|
resp, err = resty.R().SetQueryParam("digest", digest.String()).
|
||||||
SetHeader("Content-Type", "application/octet-stream").SetBody(content).Put(BaseURL + loc)
|
SetHeader("Content-Type", "application/octet-stream").SetBody(content).Put(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 201)
|
So(resp.StatusCode(), ShouldEqual, 201)
|
||||||
blobLoc := resp.Header().Get("Location")
|
blobLoc := resp.Header().Get("Location")
|
||||||
|
@ -121,27 +127,28 @@ func TestAPI(t *testing.T) {
|
||||||
So(resp.Header().Get("Content-Length"), ShouldEqual, "0")
|
So(resp.Header().Get("Content-Length"), ShouldEqual, "0")
|
||||||
So(resp.Header().Get(api.DistContentDigestKey), ShouldNotBeEmpty)
|
So(resp.Header().Get(api.DistContentDigestKey), ShouldNotBeEmpty)
|
||||||
// upload reference should now be removed
|
// upload reference should now be removed
|
||||||
resp, err = resty.R().Get(BaseURL + loc)
|
resp, err = resty.R().Get(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 404)
|
So(resp.StatusCode(), ShouldEqual, 404)
|
||||||
// blob reference should be accessible
|
// blob reference should be accessible
|
||||||
resp, err = resty.R().Get(BaseURL + blobLoc)
|
resp, err = resty.R().Get(baseURL + blobLoc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 200)
|
So(resp.StatusCode(), ShouldEqual, 200)
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("Monolithic blob upload with multiple name components", func() {
|
Convey("Monolithic blob upload with multiple name components", func() {
|
||||||
resp, err := resty.R().Post(BaseURL + "/v2/repo1/repo2/repo3/blobs/uploads/")
|
Print("\nMonolithic blob upload with multiple name components")
|
||||||
|
resp, err := resty.R().Post(baseURL + "/v2/repo1/repo2/repo3/blobs/uploads/")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 202)
|
So(resp.StatusCode(), ShouldEqual, 202)
|
||||||
loc := resp.Header().Get("Location")
|
loc := resp.Header().Get("Location")
|
||||||
So(loc, ShouldNotBeEmpty)
|
So(loc, ShouldNotBeEmpty)
|
||||||
|
|
||||||
resp, err = resty.R().Get(BaseURL + loc)
|
resp, err = resty.R().Get(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 204)
|
So(resp.StatusCode(), ShouldEqual, 204)
|
||||||
|
|
||||||
resp, err = resty.R().Get(BaseURL + "/v2/repo1/repo2/repo3/tags/list")
|
resp, err = resty.R().Get(baseURL + "/v2/repo1/repo2/repo3/tags/list")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 200)
|
So(resp.StatusCode(), ShouldEqual, 200)
|
||||||
So(resp.String(), ShouldNotBeEmpty)
|
So(resp.String(), ShouldNotBeEmpty)
|
||||||
|
@ -150,21 +157,21 @@ func TestAPI(t *testing.T) {
|
||||||
content := []byte("this is a blob")
|
content := []byte("this is a blob")
|
||||||
digest := godigest.FromBytes(content)
|
digest := godigest.FromBytes(content)
|
||||||
So(digest, ShouldNotBeNil)
|
So(digest, ShouldNotBeNil)
|
||||||
resp, err = resty.R().Put(BaseURL + loc)
|
resp, err = resty.R().Put(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 400)
|
So(resp.StatusCode(), ShouldEqual, 400)
|
||||||
// without the Content-Length should fail
|
// without the Content-Length should fail
|
||||||
resp, err = resty.R().SetQueryParam("digest", digest.String()).Put(BaseURL + loc)
|
resp, err = resty.R().SetQueryParam("digest", digest.String()).Put(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 400)
|
So(resp.StatusCode(), ShouldEqual, 400)
|
||||||
// without any data to send, should fail
|
// without any data to send, should fail
|
||||||
resp, err = resty.R().SetQueryParam("digest", digest.String()).
|
resp, err = resty.R().SetQueryParam("digest", digest.String()).
|
||||||
SetHeader("Content-Type", "application/octet-stream").Put(BaseURL + loc)
|
SetHeader("Content-Type", "application/octet-stream").Put(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 400)
|
So(resp.StatusCode(), ShouldEqual, 400)
|
||||||
// monolithic blob upload: success
|
// monolithic blob upload: success
|
||||||
resp, err = resty.R().SetQueryParam("digest", digest.String()).
|
resp, err = resty.R().SetQueryParam("digest", digest.String()).
|
||||||
SetHeader("Content-Type", "application/octet-stream").SetBody(content).Put(BaseURL + loc)
|
SetHeader("Content-Type", "application/octet-stream").SetBody(content).Put(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 201)
|
So(resp.StatusCode(), ShouldEqual, 201)
|
||||||
blobLoc := resp.Header().Get("Location")
|
blobLoc := resp.Header().Get("Location")
|
||||||
|
@ -172,17 +179,18 @@ func TestAPI(t *testing.T) {
|
||||||
So(resp.Header().Get("Content-Length"), ShouldEqual, "0")
|
So(resp.Header().Get("Content-Length"), ShouldEqual, "0")
|
||||||
So(resp.Header().Get(api.DistContentDigestKey), ShouldNotBeEmpty)
|
So(resp.Header().Get(api.DistContentDigestKey), ShouldNotBeEmpty)
|
||||||
// upload reference should now be removed
|
// upload reference should now be removed
|
||||||
resp, err = resty.R().Get(BaseURL + loc)
|
resp, err = resty.R().Get(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 404)
|
So(resp.StatusCode(), ShouldEqual, 404)
|
||||||
// blob reference should be accessible
|
// blob reference should be accessible
|
||||||
resp, err = resty.R().Get(BaseURL + blobLoc)
|
resp, err = resty.R().Get(baseURL + blobLoc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 200)
|
So(resp.StatusCode(), ShouldEqual, 200)
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("Chunked blob upload", func() {
|
Convey("Chunked blob upload", func() {
|
||||||
resp, err := resty.R().Post(BaseURL + "/v2/repo/blobs/uploads/")
|
Print("\nChunked blob upload")
|
||||||
|
resp, err := resty.R().Post(baseURL + "/v2/repo/blobs/uploads/")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 202)
|
So(resp.StatusCode(), ShouldEqual, 202)
|
||||||
loc := resp.Header().Get("Location")
|
loc := resp.Header().Get("Location")
|
||||||
|
@ -197,12 +205,12 @@ func TestAPI(t *testing.T) {
|
||||||
// write first chunk
|
// write first chunk
|
||||||
contentRange := fmt.Sprintf("%d-%d", 0, len(chunk1))
|
contentRange := fmt.Sprintf("%d-%d", 0, len(chunk1))
|
||||||
resp, err = resty.R().SetHeader("Content-Type", "application/octet-stream").
|
resp, err = resty.R().SetHeader("Content-Type", "application/octet-stream").
|
||||||
SetHeader("Content-Range", contentRange).SetBody(chunk1).Patch(BaseURL + loc)
|
SetHeader("Content-Range", contentRange).SetBody(chunk1).Patch(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 202)
|
So(resp.StatusCode(), ShouldEqual, 202)
|
||||||
|
|
||||||
// check progress
|
// check progress
|
||||||
resp, err = resty.R().Get(BaseURL + loc)
|
resp, err = resty.R().Get(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 204)
|
So(resp.StatusCode(), ShouldEqual, 204)
|
||||||
r := resp.Header().Get("Range")
|
r := resp.Header().Get("Range")
|
||||||
|
@ -212,7 +220,7 @@ func TestAPI(t *testing.T) {
|
||||||
// write same chunk should fail
|
// write same chunk should fail
|
||||||
contentRange = fmt.Sprintf("%d-%d", 0, len(chunk1))
|
contentRange = fmt.Sprintf("%d-%d", 0, len(chunk1))
|
||||||
resp, err = resty.R().SetHeader("Content-Type", "application/octet-stream").
|
resp, err = resty.R().SetHeader("Content-Type", "application/octet-stream").
|
||||||
SetHeader("Content-Range", contentRange).SetBody(chunk1).Patch(BaseURL + loc)
|
SetHeader("Content-Range", contentRange).SetBody(chunk1).Patch(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 400)
|
So(resp.StatusCode(), ShouldEqual, 400)
|
||||||
So(resp.String(), ShouldNotBeEmpty)
|
So(resp.String(), ShouldNotBeEmpty)
|
||||||
|
@ -229,7 +237,7 @@ func TestAPI(t *testing.T) {
|
||||||
contentRange = fmt.Sprintf("%d-%d", len(chunk1), len(buf.Bytes()))
|
contentRange = fmt.Sprintf("%d-%d", len(chunk1), len(buf.Bytes()))
|
||||||
resp, err = resty.R().SetQueryParam("digest", digest.String()).
|
resp, err = resty.R().SetQueryParam("digest", digest.String()).
|
||||||
SetHeader("Content-Range", contentRange).
|
SetHeader("Content-Range", contentRange).
|
||||||
SetHeader("Content-Type", "application/octet-stream").SetBody(chunk2).Put(BaseURL + loc)
|
SetHeader("Content-Type", "application/octet-stream").SetBody(chunk2).Put(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 201)
|
So(resp.StatusCode(), ShouldEqual, 201)
|
||||||
blobLoc := resp.Header().Get("Location")
|
blobLoc := resp.Header().Get("Location")
|
||||||
|
@ -239,17 +247,18 @@ func TestAPI(t *testing.T) {
|
||||||
So(resp.Header().Get("Content-Length"), ShouldEqual, "0")
|
So(resp.Header().Get("Content-Length"), ShouldEqual, "0")
|
||||||
So(resp.Header().Get(api.DistContentDigestKey), ShouldNotBeEmpty)
|
So(resp.Header().Get(api.DistContentDigestKey), ShouldNotBeEmpty)
|
||||||
// upload reference should now be removed
|
// upload reference should now be removed
|
||||||
resp, err = resty.R().Get(BaseURL + loc)
|
resp, err = resty.R().Get(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 404)
|
So(resp.StatusCode(), ShouldEqual, 404)
|
||||||
// blob reference should be accessible
|
// blob reference should be accessible
|
||||||
resp, err = resty.R().Get(BaseURL + blobLoc)
|
resp, err = resty.R().Get(baseURL + blobLoc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 200)
|
So(resp.StatusCode(), ShouldEqual, 200)
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("Chunked blob upload with multiple name components", func() {
|
Convey("Chunked blob upload with multiple name components", func() {
|
||||||
resp, err := resty.R().Post(BaseURL + "/v2/repo4/repo5/repo6/blobs/uploads/")
|
Print("\nChunked blob upload with multiple name components")
|
||||||
|
resp, err := resty.R().Post(baseURL + "/v2/repo4/repo5/repo6/blobs/uploads/")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 202)
|
So(resp.StatusCode(), ShouldEqual, 202)
|
||||||
loc := resp.Header().Get("Location")
|
loc := resp.Header().Get("Location")
|
||||||
|
@ -264,12 +273,12 @@ func TestAPI(t *testing.T) {
|
||||||
// write first chunk
|
// write first chunk
|
||||||
contentRange := fmt.Sprintf("%d-%d", 0, len(chunk1))
|
contentRange := fmt.Sprintf("%d-%d", 0, len(chunk1))
|
||||||
resp, err = resty.R().SetHeader("Content-Type", "application/octet-stream").
|
resp, err = resty.R().SetHeader("Content-Type", "application/octet-stream").
|
||||||
SetHeader("Content-Range", contentRange).SetBody(chunk1).Patch(BaseURL + loc)
|
SetHeader("Content-Range", contentRange).SetBody(chunk1).Patch(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 202)
|
So(resp.StatusCode(), ShouldEqual, 202)
|
||||||
|
|
||||||
// check progress
|
// check progress
|
||||||
resp, err = resty.R().Get(BaseURL + loc)
|
resp, err = resty.R().Get(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 204)
|
So(resp.StatusCode(), ShouldEqual, 204)
|
||||||
r := resp.Header().Get("Range")
|
r := resp.Header().Get("Range")
|
||||||
|
@ -279,7 +288,7 @@ func TestAPI(t *testing.T) {
|
||||||
// write same chunk should fail
|
// write same chunk should fail
|
||||||
contentRange = fmt.Sprintf("%d-%d", 0, len(chunk1))
|
contentRange = fmt.Sprintf("%d-%d", 0, len(chunk1))
|
||||||
resp, err = resty.R().SetHeader("Content-Type", "application/octet-stream").
|
resp, err = resty.R().SetHeader("Content-Type", "application/octet-stream").
|
||||||
SetHeader("Content-Range", contentRange).SetBody(chunk1).Patch(BaseURL + loc)
|
SetHeader("Content-Range", contentRange).SetBody(chunk1).Patch(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 400)
|
So(resp.StatusCode(), ShouldEqual, 400)
|
||||||
So(resp.String(), ShouldNotBeEmpty)
|
So(resp.String(), ShouldNotBeEmpty)
|
||||||
|
@ -296,7 +305,7 @@ func TestAPI(t *testing.T) {
|
||||||
contentRange = fmt.Sprintf("%d-%d", len(chunk1), len(buf.Bytes()))
|
contentRange = fmt.Sprintf("%d-%d", len(chunk1), len(buf.Bytes()))
|
||||||
resp, err = resty.R().SetQueryParam("digest", digest.String()).
|
resp, err = resty.R().SetQueryParam("digest", digest.String()).
|
||||||
SetHeader("Content-Range", contentRange).
|
SetHeader("Content-Range", contentRange).
|
||||||
SetHeader("Content-Type", "application/octet-stream").SetBody(chunk2).Put(BaseURL + loc)
|
SetHeader("Content-Type", "application/octet-stream").SetBody(chunk2).Put(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 201)
|
So(resp.StatusCode(), ShouldEqual, 201)
|
||||||
blobLoc := resp.Header().Get("Location")
|
blobLoc := resp.Header().Get("Location")
|
||||||
|
@ -306,32 +315,34 @@ func TestAPI(t *testing.T) {
|
||||||
So(resp.Header().Get("Content-Length"), ShouldEqual, "0")
|
So(resp.Header().Get("Content-Length"), ShouldEqual, "0")
|
||||||
So(resp.Header().Get(api.DistContentDigestKey), ShouldNotBeEmpty)
|
So(resp.Header().Get(api.DistContentDigestKey), ShouldNotBeEmpty)
|
||||||
// upload reference should now be removed
|
// upload reference should now be removed
|
||||||
resp, err = resty.R().Get(BaseURL + loc)
|
resp, err = resty.R().Get(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 404)
|
So(resp.StatusCode(), ShouldEqual, 404)
|
||||||
// blob reference should be accessible
|
// blob reference should be accessible
|
||||||
resp, err = resty.R().Get(BaseURL + blobLoc)
|
resp, err = resty.R().Get(baseURL + blobLoc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 200)
|
So(resp.StatusCode(), ShouldEqual, 200)
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("Create and delete uploads", func() {
|
Convey("Create and delete uploads", func() {
|
||||||
|
Print("\nCreate and delete uploads")
|
||||||
// create a upload
|
// create a upload
|
||||||
resp, err := resty.R().Post(BaseURL + "/v2/repo/blobs/uploads/")
|
resp, err := resty.R().Post(baseURL + "/v2/repo/blobs/uploads/")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 202)
|
So(resp.StatusCode(), ShouldEqual, 202)
|
||||||
loc := resp.Header().Get("Location")
|
loc := resp.Header().Get("Location")
|
||||||
So(loc, ShouldNotBeEmpty)
|
So(loc, ShouldNotBeEmpty)
|
||||||
|
|
||||||
// delete this upload
|
// delete this upload
|
||||||
resp, err = resty.R().Delete(BaseURL + loc)
|
resp, err = resty.R().Delete(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 200)
|
So(resp.StatusCode(), ShouldEqual, 200)
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("Create and delete blobs", func() {
|
Convey("Create and delete blobs", func() {
|
||||||
|
Print("\nCreate and delete blobs")
|
||||||
// create a upload
|
// create a upload
|
||||||
resp, err := resty.R().Post(BaseURL + "/v2/repo/blobs/uploads/")
|
resp, err := resty.R().Post(baseURL + "/v2/repo/blobs/uploads/")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 202)
|
So(resp.StatusCode(), ShouldEqual, 202)
|
||||||
loc := resp.Header().Get("Location")
|
loc := resp.Header().Get("Location")
|
||||||
|
@ -342,7 +353,7 @@ func TestAPI(t *testing.T) {
|
||||||
So(digest, ShouldNotBeNil)
|
So(digest, ShouldNotBeNil)
|
||||||
// monolithic blob upload
|
// monolithic blob upload
|
||||||
resp, err = resty.R().SetQueryParam("digest", digest.String()).
|
resp, err = resty.R().SetQueryParam("digest", digest.String()).
|
||||||
SetHeader("Content-Type", "application/octet-stream").SetBody(content).Put(BaseURL + loc)
|
SetHeader("Content-Type", "application/octet-stream").SetBody(content).Put(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 201)
|
So(resp.StatusCode(), ShouldEqual, 201)
|
||||||
blobLoc := resp.Header().Get("Location")
|
blobLoc := resp.Header().Get("Location")
|
||||||
|
@ -350,21 +361,22 @@ func TestAPI(t *testing.T) {
|
||||||
So(resp.Header().Get(api.DistContentDigestKey), ShouldNotBeEmpty)
|
So(resp.Header().Get(api.DistContentDigestKey), ShouldNotBeEmpty)
|
||||||
|
|
||||||
// delete this blob
|
// delete this blob
|
||||||
resp, err = resty.R().Delete(BaseURL + blobLoc)
|
resp, err = resty.R().Delete(baseURL + blobLoc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 202)
|
So(resp.StatusCode(), ShouldEqual, 202)
|
||||||
So(resp.Header().Get("Content-Length"), ShouldEqual, "0")
|
So(resp.Header().Get("Content-Length"), ShouldEqual, "0")
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("Manifests", func() {
|
Convey("Manifests", func() {
|
||||||
|
Print("\nManifests")
|
||||||
// create a blob/layer
|
// create a blob/layer
|
||||||
resp, err := resty.R().Post(BaseURL + "/v2/repo/blobs/uploads/")
|
resp, err := resty.R().Post(baseURL + "/v2/repo/blobs/uploads/")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 202)
|
So(resp.StatusCode(), ShouldEqual, 202)
|
||||||
loc := resp.Header().Get("Location")
|
loc := resp.Header().Get("Location")
|
||||||
So(loc, ShouldNotBeEmpty)
|
So(loc, ShouldNotBeEmpty)
|
||||||
|
|
||||||
resp, err = resty.R().Get(BaseURL + loc)
|
resp, err = resty.R().Get(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 204)
|
So(resp.StatusCode(), ShouldEqual, 204)
|
||||||
content := []byte("this is a blob")
|
content := []byte("this is a blob")
|
||||||
|
@ -372,7 +384,7 @@ func TestAPI(t *testing.T) {
|
||||||
So(digest, ShouldNotBeNil)
|
So(digest, ShouldNotBeNil)
|
||||||
// monolithic blob upload: success
|
// monolithic blob upload: success
|
||||||
resp, err = resty.R().SetQueryParam("digest", digest.String()).
|
resp, err = resty.R().SetQueryParam("digest", digest.String()).
|
||||||
SetHeader("Content-Type", "application/octet-stream").SetBody(content).Put(BaseURL + loc)
|
SetHeader("Content-Type", "application/octet-stream").SetBody(content).Put(baseURL + loc)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 201)
|
So(resp.StatusCode(), ShouldEqual, 201)
|
||||||
blobLoc := resp.Header().Get("Location")
|
blobLoc := resp.Header().Get("Location")
|
||||||
|
@ -387,7 +399,7 @@ func TestAPI(t *testing.T) {
|
||||||
digest = godigest.FromBytes(content)
|
digest = godigest.FromBytes(content)
|
||||||
So(digest, ShouldNotBeNil)
|
So(digest, ShouldNotBeNil)
|
||||||
resp, err = resty.R().SetHeader("Content-Type", "application/vnd.oci.image.manifest.v1+json").
|
resp, err = resty.R().SetHeader("Content-Type", "application/vnd.oci.image.manifest.v1+json").
|
||||||
SetBody(content).Put(BaseURL + "/v2/repo/manifests/test:1.0")
|
SetBody(content).Put(baseURL + "/v2/repo/manifests/test:1.0")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 201)
|
So(resp.StatusCode(), ShouldEqual, 201)
|
||||||
d := resp.Header().Get(api.DistContentDigestKey)
|
d := resp.Header().Get(api.DistContentDigestKey)
|
||||||
|
@ -395,76 +407,47 @@ func TestAPI(t *testing.T) {
|
||||||
So(d, ShouldEqual, digest.String())
|
So(d, ShouldEqual, digest.String())
|
||||||
|
|
||||||
// check/get by tag
|
// check/get by tag
|
||||||
resp, err = resty.R().Head(BaseURL + "/v2/repo/manifests/test:1.0")
|
resp, err = resty.R().Head(baseURL + "/v2/repo/manifests/test:1.0")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 200)
|
So(resp.StatusCode(), ShouldEqual, 200)
|
||||||
resp, err = resty.R().Get(BaseURL + "/v2/repo/manifests/test:1.0")
|
resp, err = resty.R().Get(baseURL + "/v2/repo/manifests/test:1.0")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 200)
|
So(resp.StatusCode(), ShouldEqual, 200)
|
||||||
So(resp.Body(), ShouldNotBeEmpty)
|
So(resp.Body(), ShouldNotBeEmpty)
|
||||||
// check/get by reference
|
// check/get by reference
|
||||||
resp, err = resty.R().Head(BaseURL + "/v2/repo/manifests/" + digest.String())
|
resp, err = resty.R().Head(baseURL + "/v2/repo/manifests/" + digest.String())
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 200)
|
So(resp.StatusCode(), ShouldEqual, 200)
|
||||||
resp, err = resty.R().Get(BaseURL + "/v2/repo/manifests/" + digest.String())
|
resp, err = resty.R().Get(baseURL + "/v2/repo/manifests/" + digest.String())
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 200)
|
So(resp.StatusCode(), ShouldEqual, 200)
|
||||||
So(resp.Body(), ShouldNotBeEmpty)
|
So(resp.Body(), ShouldNotBeEmpty)
|
||||||
|
|
||||||
// delete manifest
|
// delete manifest
|
||||||
resp, err = resty.R().Delete(BaseURL + "/v2/repo/manifests/test:1.0")
|
resp, err = resty.R().Delete(baseURL + "/v2/repo/manifests/test:1.0")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 200)
|
So(resp.StatusCode(), ShouldEqual, 200)
|
||||||
// delete again should fail
|
// delete again should fail
|
||||||
resp, err = resty.R().Delete(BaseURL + "/v2/repo/manifests/" + digest.String())
|
resp, err = resty.R().Delete(baseURL + "/v2/repo/manifests/" + digest.String())
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 404)
|
So(resp.StatusCode(), ShouldEqual, 404)
|
||||||
|
|
||||||
// check/get by tag
|
// check/get by tag
|
||||||
resp, err = resty.R().Head(BaseURL + "/v2/repo/manifests/test:1.0")
|
resp, err = resty.R().Head(baseURL + "/v2/repo/manifests/test:1.0")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 404)
|
So(resp.StatusCode(), ShouldEqual, 404)
|
||||||
resp, err = resty.R().Get(BaseURL + "/v2/repo/manifests/test:1.0")
|
resp, err = resty.R().Get(baseURL + "/v2/repo/manifests/test:1.0")
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 404)
|
So(resp.StatusCode(), ShouldEqual, 404)
|
||||||
So(resp.Body(), ShouldNotBeEmpty)
|
So(resp.Body(), ShouldNotBeEmpty)
|
||||||
// check/get by reference
|
// check/get by reference
|
||||||
resp, err = resty.R().Head(BaseURL + "/v2/repo/manifests/" + digest.String())
|
resp, err = resty.R().Head(baseURL + "/v2/repo/manifests/" + digest.String())
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 404)
|
So(resp.StatusCode(), ShouldEqual, 404)
|
||||||
resp, err = resty.R().Get(BaseURL + "/v2/repo/manifests/" + digest.String())
|
resp, err = resty.R().Get(baseURL + "/v2/repo/manifests/" + digest.String())
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, 404)
|
So(resp.StatusCode(), ShouldEqual, 404)
|
||||||
So(resp.Body(), ShouldNotBeEmpty)
|
So(resp.Body(), ShouldNotBeEmpty)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
config := api.NewConfig()
|
|
||||||
c := api.NewController(config)
|
|
||||||
dir, err := ioutil.TempDir("", "oci-repo-test")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
//defer os.RemoveAll(dir)
|
|
||||||
c.Config.Storage.RootDirectory = dir
|
|
||||||
go func() {
|
|
||||||
// this blocks
|
|
||||||
if err := c.Run(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
for {
|
|
||||||
// poll until ready
|
|
||||||
resp, _ := resty.R().Get(BaseURL)
|
|
||||||
if resp.StatusCode() == 404 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
}
|
|
||||||
status := m.Run()
|
|
||||||
ctx := context.Background()
|
|
||||||
_ = c.Server.Shutdown(ctx)
|
|
||||||
os.Exit(status)
|
|
||||||
}
|
|
57
pkg/compliance/v1_0_0/check_test.go
Normal file
57
pkg/compliance/v1_0_0/check_test.go
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package v1_0_0_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/anuvu/zot/pkg/api"
|
||||||
|
"github.com/anuvu/zot/pkg/compliance"
|
||||||
|
"github.com/anuvu/zot/pkg/compliance/v1_0_0"
|
||||||
|
"gopkg.in/resty.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
Address = "127.0.0.1"
|
||||||
|
Port = "8080"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWorkflows(t *testing.T) {
|
||||||
|
v1_0_0.CheckWorkflows(t, &compliance.Config{Address: Address, Port: Port})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
config := api.NewConfig()
|
||||||
|
config.HTTP.Address = Address
|
||||||
|
config.HTTP.Port = Port
|
||||||
|
c := api.NewController(config)
|
||||||
|
dir, err := ioutil.TempDir("", "oci-repo-test")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
//defer os.RemoveAll(dir)
|
||||||
|
c.Config.Storage.RootDirectory = dir
|
||||||
|
go func() {
|
||||||
|
// this blocks
|
||||||
|
if err := c.Run(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
BaseURL := fmt.Sprintf("http://%s:%s", Address, Port)
|
||||||
|
for {
|
||||||
|
// poll until ready
|
||||||
|
resp, _ := resty.R().Get(BaseURL)
|
||||||
|
if resp.StatusCode() == 404 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
status := m.Run()
|
||||||
|
ctx := context.Background()
|
||||||
|
_ = c.Server.Shutdown(ctx)
|
||||||
|
os.Exit(status)
|
||||||
|
}
|
Loading…
Reference in a new issue