mirror of
https://github.com/project-zot/zot.git
synced 2024-12-23 22:27:35 -05:00
05f75e041c
Signed-off-by: Nicol Draghici <idraghic@cisco.com>
1418 lines
38 KiB
Go
1418 lines
38 KiB
Go
//go:build sync && scrub && metrics && search && lint
|
|
// +build sync,scrub,metrics,search,lint
|
|
|
|
package api_test
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/gorilla/mux"
|
|
godigest "github.com/opencontainers/go-digest"
|
|
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
. "github.com/smartystreets/goconvey/convey"
|
|
|
|
zerr "zotregistry.io/zot/errors"
|
|
"zotregistry.io/zot/pkg/api"
|
|
"zotregistry.io/zot/pkg/api/config"
|
|
"zotregistry.io/zot/pkg/api/constants"
|
|
localCtx "zotregistry.io/zot/pkg/requestcontext"
|
|
"zotregistry.io/zot/pkg/storage"
|
|
"zotregistry.io/zot/pkg/test"
|
|
"zotregistry.io/zot/pkg/test/mocks"
|
|
)
|
|
|
|
var ErrUnexpectedError = errors.New("error: unexpected error")
|
|
|
|
func TestRoutes(t *testing.T) {
|
|
Convey("Make a new controller", t, func() {
|
|
port := test.GetFreePort()
|
|
baseURL := test.GetBaseURL(port)
|
|
conf := config.New()
|
|
conf.HTTP.Port = port
|
|
|
|
ctlr := api.NewController(conf)
|
|
|
|
ctlr.Config.Storage.RootDirectory = t.TempDir()
|
|
ctlr.Config.Storage.Commit = true
|
|
|
|
err := test.CopyFiles("../../test/data", ctlr.Config.Storage.RootDirectory)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
cm := test.NewControllerManager(ctlr)
|
|
cm.StartAndWait(port)
|
|
defer cm.StopServer()
|
|
|
|
rthdlr := api.NewRouteHandler(ctlr)
|
|
|
|
// NOTE: the url or method itself doesn't matter below since we are calling the handlers directly,
|
|
// so path routing is bypassed
|
|
|
|
Convey("List repositories authz error", func() {
|
|
var invalid struct{}
|
|
|
|
ctx := context.TODO()
|
|
key := localCtx.GetContextKey()
|
|
ctx = context.WithValue(ctx, key, invalid)
|
|
|
|
request, _ := http.NewRequestWithContext(ctx, http.MethodGet, baseURL, nil)
|
|
request = mux.SetURLVars(request, map[string]string{
|
|
"name": "test",
|
|
"reference": "b8b1231908844a55c251211c7a67ae3c809fb86a081a8eeb4a715e6d7d65625c",
|
|
})
|
|
response := httptest.NewRecorder()
|
|
|
|
rthdlr.ListRepositories(response, request)
|
|
|
|
resp := response.Result()
|
|
|
|
defer resp.Body.Close()
|
|
So(resp, ShouldNotBeNil)
|
|
So(resp.StatusCode, ShouldEqual, http.StatusInternalServerError)
|
|
})
|
|
|
|
Convey("Delete manifest authz error", func() {
|
|
var invalid struct{}
|
|
|
|
ctx := context.TODO()
|
|
key := localCtx.GetContextKey()
|
|
ctx = context.WithValue(ctx, key, invalid)
|
|
|
|
request, _ := http.NewRequestWithContext(ctx, http.MethodGet, baseURL, nil)
|
|
request = mux.SetURLVars(request, map[string]string{
|
|
"name": "test",
|
|
"reference": "b8b1231908844a55c251211c7a67ae3c809fb86a081a8eeb4a715e6d7d65625c",
|
|
})
|
|
response := httptest.NewRecorder()
|
|
|
|
rthdlr.DeleteManifest(response, request)
|
|
|
|
resp := response.Result()
|
|
|
|
defer resp.Body.Close()
|
|
So(resp, ShouldNotBeNil)
|
|
So(resp.StatusCode, ShouldEqual, http.StatusInternalServerError)
|
|
})
|
|
|
|
Convey("Get manifest", func() {
|
|
// overwrite controller storage
|
|
ctlr.StoreController.DefaultStore = &mocks.MockedImageStore{
|
|
GetImageManifestFn: func(repo string, reference string) ([]byte, godigest.Digest, string, error) {
|
|
return []byte{}, "", "", zerr.ErrRepoBadVersion
|
|
},
|
|
}
|
|
|
|
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodGet, baseURL, nil)
|
|
request = mux.SetURLVars(request, map[string]string{
|
|
"name": "test",
|
|
"reference": "b8b1231908844a55c251211c7a67ae3c809fb86a081a8eeb4a715e6d7d65625c",
|
|
})
|
|
response := httptest.NewRecorder()
|
|
|
|
rthdlr.GetManifest(response, request)
|
|
|
|
resp := response.Result()
|
|
|
|
defer resp.Body.Close()
|
|
So(resp, ShouldNotBeNil)
|
|
So(resp.StatusCode, ShouldEqual, http.StatusNotFound)
|
|
})
|
|
|
|
Convey("UpdateManifest ", func() {
|
|
testUpdateManifest := func(urlVars map[string]string, ism *mocks.MockedImageStore) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
str := []byte("test")
|
|
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodPut, baseURL, bytes.NewBuffer(str))
|
|
request = mux.SetURLVars(request, urlVars)
|
|
request.Header.Add("Content-Type", ispec.MediaTypeImageManifest)
|
|
response := httptest.NewRecorder()
|
|
|
|
rthdlr.UpdateManifest(response, request)
|
|
|
|
resp := response.Result()
|
|
defer resp.Body.Close()
|
|
|
|
return resp.StatusCode
|
|
}
|
|
// repo not found
|
|
statusCode := testUpdateManifest(
|
|
map[string]string{
|
|
"name": "test",
|
|
"reference": "reference",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
PutImageManifestFn: func(repo, reference, mediaType string, body []byte) (godigest.Digest, error) {
|
|
return "", zerr.ErrRepoNotFound
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusNotFound)
|
|
// ErrManifestNotFound
|
|
statusCode = testUpdateManifest(
|
|
map[string]string{
|
|
"name": "test",
|
|
"reference": "reference",
|
|
},
|
|
|
|
&mocks.MockedImageStore{
|
|
PutImageManifestFn: func(repo, reference, mediaType string, body []byte) (godigest.Digest, error) {
|
|
return "", zerr.ErrManifestNotFound
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusNotFound)
|
|
// ErrBadManifest
|
|
statusCode = testUpdateManifest(
|
|
map[string]string{
|
|
"name": "test",
|
|
"reference": "reference",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
PutImageManifestFn: func(repo, reference, mediaType string, body []byte) (godigest.Digest, error) {
|
|
return "", zerr.ErrBadManifest
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusBadRequest)
|
|
// ErrBlobNotFound
|
|
statusCode = testUpdateManifest(
|
|
map[string]string{
|
|
"name": "test",
|
|
"reference": "reference",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
PutImageManifestFn: func(repo, reference, mediaType string, body []byte) (godigest.Digest, error) {
|
|
return "", zerr.ErrBlobNotFound
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusBadRequest)
|
|
|
|
// ErrRepoBadVersion
|
|
statusCode = testUpdateManifest(
|
|
map[string]string{
|
|
"name": "test",
|
|
"reference": "reference",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
PutImageManifestFn: func(repo, reference, mediaType string, body []byte) (godigest.Digest, error) {
|
|
return "", zerr.ErrRepoBadVersion
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusInternalServerError)
|
|
})
|
|
|
|
Convey("DeleteManifest", func() {
|
|
testDeleteManifest := func(headers map[string]string, urlVars map[string]string, ism *mocks.MockedImageStore) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
request, _ := http.NewRequestWithContext(context.Background(), http.MethodDelete, baseURL, nil)
|
|
request = mux.SetURLVars(request, urlVars)
|
|
for k, v := range headers {
|
|
request.Header.Add(k, v)
|
|
}
|
|
response := httptest.NewRecorder()
|
|
|
|
rthdlr.DeleteManifest(response, request)
|
|
|
|
resp := response.Result()
|
|
defer resp.Body.Close()
|
|
|
|
return resp.StatusCode
|
|
}
|
|
|
|
// ErrRepoNotFound
|
|
statusCode := testDeleteManifest(
|
|
map[string]string{},
|
|
map[string]string{
|
|
"name": "ErrManifestNotFound",
|
|
"reference": "reference",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
DeleteImageManifestFn: func(repo, reference string, detectCollision bool) error {
|
|
return zerr.ErrRepoNotFound
|
|
},
|
|
},
|
|
)
|
|
So(statusCode, ShouldEqual, http.StatusBadRequest)
|
|
|
|
// ErrManifestNotFound
|
|
statusCode = testDeleteManifest(
|
|
map[string]string{},
|
|
map[string]string{
|
|
"name": "ErrManifestNotFound",
|
|
"reference": "reference",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
DeleteImageManifestFn: func(repo, reference string, detectCollision bool) error {
|
|
return zerr.ErrManifestNotFound
|
|
},
|
|
},
|
|
)
|
|
So(statusCode, ShouldEqual, http.StatusNotFound)
|
|
|
|
// ErrUnexpectedError
|
|
statusCode = testDeleteManifest(
|
|
map[string]string{},
|
|
map[string]string{
|
|
"name": "ErrUnexpectedError",
|
|
"reference": "reference",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
DeleteImageManifestFn: func(repo, reference string, detectCollision bool) error {
|
|
return ErrUnexpectedError
|
|
},
|
|
},
|
|
)
|
|
So(statusCode, ShouldEqual, http.StatusInternalServerError)
|
|
|
|
// ErrBadManifest
|
|
statusCode = testDeleteManifest(
|
|
map[string]string{},
|
|
map[string]string{
|
|
"name": "ErrBadManifest",
|
|
"reference": "reference",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
DeleteImageManifestFn: func(repo, reference string, detectCollision bool) error {
|
|
return zerr.ErrBadManifest
|
|
},
|
|
},
|
|
)
|
|
So(statusCode, ShouldEqual, http.StatusBadRequest)
|
|
})
|
|
|
|
Convey("DeleteBlob", func() {
|
|
testDeleteBlob := func(urlVars map[string]string, ism *mocks.MockedImageStore) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodDelete, baseURL, nil)
|
|
request = mux.SetURLVars(request, urlVars)
|
|
response := httptest.NewRecorder()
|
|
|
|
rthdlr.DeleteBlob(response, request)
|
|
|
|
resp := response.Result()
|
|
defer resp.Body.Close()
|
|
|
|
return resp.StatusCode
|
|
}
|
|
|
|
// ErrUnexpectedError
|
|
statusCode := testDeleteBlob(
|
|
map[string]string{
|
|
"name": "ErrUnexpectedError",
|
|
"digest": test.GetTestBlobDigest("zot-cve-test", "layer").String(),
|
|
},
|
|
&mocks.MockedImageStore{
|
|
DeleteBlobFn: func(repo string, digest godigest.Digest) error {
|
|
return ErrUnexpectedError
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusInternalServerError)
|
|
|
|
statusCode = testDeleteBlob(
|
|
map[string]string{
|
|
"name": "ErrBadBlobDigest",
|
|
"digest": "sha256:7b8437f04f83f084b7ed68ad8c4a4947e12fc4e1b006b38129bac89114ec3621",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
DeleteBlobFn: func(repo string, digest godigest.Digest) error {
|
|
return zerr.ErrBadBlobDigest
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusBadRequest)
|
|
|
|
// ErrBlobNotFound
|
|
statusCode = testDeleteBlob(
|
|
map[string]string{
|
|
"name": "ErrBlobNotFound",
|
|
"digest": test.GetTestBlobDigest("zot-cve-test", "layer").String(),
|
|
},
|
|
&mocks.MockedImageStore{
|
|
DeleteBlobFn: func(repo string, digest godigest.Digest) error {
|
|
return zerr.ErrBlobNotFound
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusNotFound)
|
|
|
|
// ErrRepoNotFound
|
|
statusCode = testDeleteBlob(
|
|
map[string]string{
|
|
"name": "ErrRepoNotFound",
|
|
"digest": test.GetTestBlobDigest("zot-cve-test", "layer").String(),
|
|
},
|
|
&mocks.MockedImageStore{
|
|
DeleteBlobFn: func(repo string, digest godigest.Digest) error {
|
|
return zerr.ErrRepoNotFound
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusNotFound)
|
|
})
|
|
|
|
// Check Blob
|
|
Convey("CheckBlob", func() {
|
|
testCheckBlob := func(urlVars map[string]string, ism *mocks.MockedImageStore) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodHead, baseURL, nil)
|
|
request = mux.SetURLVars(request, urlVars)
|
|
response := httptest.NewRecorder()
|
|
|
|
rthdlr.CheckBlob(response, request)
|
|
|
|
resp := response.Result()
|
|
defer resp.Body.Close()
|
|
|
|
return resp.StatusCode
|
|
}
|
|
|
|
// ErrBadBlobDigest
|
|
statusCode := testCheckBlob(
|
|
map[string]string{
|
|
"name": "ErrBadBlobDigest",
|
|
"digest": "1234",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
CheckBlobFn: func(repo string, digest godigest.Digest) (bool, int64, error) {
|
|
return true, 0, zerr.ErrBadBlobDigest
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusBadRequest)
|
|
|
|
// ErrRepoNotFound
|
|
statusCode = testCheckBlob(
|
|
map[string]string{
|
|
"name": "ErrRepoNotFound",
|
|
"digest": "1234",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
CheckBlobFn: func(repo string, digest godigest.Digest) (bool, int64, error) {
|
|
return true, 0, zerr.ErrRepoNotFound
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusNotFound)
|
|
|
|
// ErrBlobNotFound
|
|
statusCode = testCheckBlob(
|
|
map[string]string{
|
|
"name": "ErrBlobNotFound",
|
|
"digest": "1234",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
CheckBlobFn: func(repo string, digest godigest.Digest) (bool, int64, error) {
|
|
return true, 0, zerr.ErrBlobNotFound
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusNotFound)
|
|
|
|
// ErrUnexpectedError
|
|
statusCode = testCheckBlob(
|
|
map[string]string{
|
|
"name": "ErrUnexpectedError",
|
|
"digest": "1234",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
CheckBlobFn: func(repo string, digest godigest.Digest) (bool, int64, error) {
|
|
return true, 0, ErrUnexpectedError
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusInternalServerError)
|
|
|
|
// Error Check Blob is not ok
|
|
statusCode = testCheckBlob(
|
|
map[string]string{
|
|
"name": "Check Blob Not Ok",
|
|
"digest": "1234",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
CheckBlobFn: func(repo string, digest godigest.Digest) (bool, int64, error) {
|
|
return false, 0, nil
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusNotFound)
|
|
})
|
|
|
|
Convey("GetBlob", func() {
|
|
testGetBlob := func(urlVars map[string]string, ism *mocks.MockedImageStore) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodGet, baseURL, nil)
|
|
request = mux.SetURLVars(request, urlVars)
|
|
response := httptest.NewRecorder()
|
|
|
|
rthdlr.GetBlob(response, request)
|
|
|
|
resp := response.Result()
|
|
defer resp.Body.Close()
|
|
|
|
return resp.StatusCode
|
|
}
|
|
// ErrRepoNotFound
|
|
statusCode := testGetBlob(
|
|
map[string]string{
|
|
"name": "ErrRepoNotFound",
|
|
"digest": test.GetTestBlobDigest("zot-cve-test", "layer").String(),
|
|
},
|
|
&mocks.MockedImageStore{
|
|
GetBlobFn: func(repo string, digest godigest.Digest, mediaType string) (io.ReadCloser, int64, error) {
|
|
return io.NopCloser(bytes.NewBuffer([]byte(""))), 0, zerr.ErrRepoNotFound
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusNotFound)
|
|
|
|
// ErrRepoNotFound
|
|
statusCode = testGetBlob(
|
|
map[string]string{
|
|
"name": "ErrRepoNotFound",
|
|
"digest": test.GetTestBlobDigest("zot-cve-test", "layer").String(),
|
|
},
|
|
&mocks.MockedImageStore{
|
|
GetBlobFn: func(repo string, digest godigest.Digest, mediaType string) (io.ReadCloser, int64, error) {
|
|
return io.NopCloser(bytes.NewBuffer([]byte(""))), 0, zerr.ErrBadBlobDigest
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusBadRequest)
|
|
})
|
|
|
|
Convey("CreateBlobUpload", func() {
|
|
testCreateBlobUpload := func(
|
|
query []struct{ k, v string },
|
|
headers map[string]string,
|
|
ism *mocks.MockedImageStore,
|
|
) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodPost, baseURL, nil)
|
|
request = mux.SetURLVars(request,
|
|
map[string]string{
|
|
"name": "test",
|
|
"mount": "1234",
|
|
})
|
|
|
|
q := request.URL.Query()
|
|
for _, qe := range query {
|
|
q.Add(qe.k, qe.v)
|
|
}
|
|
request.URL.RawQuery = q.Encode()
|
|
|
|
for k, v := range headers {
|
|
request.Header.Add(k, v)
|
|
}
|
|
|
|
response := httptest.NewRecorder()
|
|
|
|
rthdlr.CreateBlobUpload(response, request)
|
|
|
|
resp := response.Result()
|
|
defer resp.Body.Close()
|
|
|
|
return resp.StatusCode
|
|
}
|
|
|
|
// ErrRepoNotFound
|
|
statusCode := testCreateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"mount", "1234"},
|
|
},
|
|
map[string]string{},
|
|
&mocks.MockedImageStore{
|
|
NewBlobUploadFn: func(repo string) (string, error) {
|
|
return "", zerr.ErrRepoNotFound
|
|
},
|
|
CheckBlobFn: func(repo string, digest godigest.Digest) (bool, int64, error) {
|
|
return true, 0, zerr.ErrRepoNotFound
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusNotFound)
|
|
|
|
// a full blob upload if multiple digests are present
|
|
statusCode = testCreateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", "1234"},
|
|
{"digest", "5234"},
|
|
},
|
|
map[string]string{},
|
|
&mocks.MockedImageStore{
|
|
NewBlobUploadFn: func(repo string) (string, error) {
|
|
return "", zerr.ErrRepoNotFound
|
|
},
|
|
CheckBlobFn: func(repo string, digest godigest.Digest) (bool, int64, error) {
|
|
return true, 0, zerr.ErrRepoNotFound
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusBadRequest)
|
|
|
|
// a full blob upload if content type is wrong
|
|
statusCode = testCreateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", "1234"},
|
|
},
|
|
map[string]string{
|
|
"Content-Type": "badContentType",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
NewBlobUploadFn: func(repo string) (string, error) {
|
|
return "", zerr.ErrRepoNotFound
|
|
},
|
|
CheckBlobFn: func(repo string, digest godigest.Digest) (bool, int64, error) {
|
|
return true, 0, zerr.ErrRepoNotFound
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusUnsupportedMediaType)
|
|
|
|
// digest prezent imgStore err
|
|
statusCode = testCreateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", "1234"},
|
|
},
|
|
map[string]string{
|
|
"Content-Type": constants.BinaryMediaType,
|
|
"Content-Length": "100",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
FullBlobUploadFn: func(repo string, body io.Reader, digest godigest.Digest) (string, int64, error) {
|
|
return "session", 0, zerr.ErrBadBlobDigest
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusInternalServerError)
|
|
|
|
// digest prezent bad length
|
|
statusCode = testCreateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", "1234"},
|
|
},
|
|
map[string]string{
|
|
"Content-Type": constants.BinaryMediaType,
|
|
"Content-Length": "100",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
FullBlobUploadFn: func(repo string, body io.Reader, digest godigest.Digest) (string, int64, error) {
|
|
return "session", 20, nil
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusInternalServerError)
|
|
|
|
// newBlobUpload not found
|
|
statusCode = testCreateBlobUpload(
|
|
[]struct{ k, v string }{},
|
|
map[string]string{
|
|
"Content-Type": constants.BinaryMediaType,
|
|
"Content-Length": "100",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
NewBlobUploadFn: func(repo string) (string, error) {
|
|
return "", zerr.ErrRepoNotFound
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusNotFound)
|
|
|
|
// newBlobUpload unexpected error
|
|
statusCode = testCreateBlobUpload(
|
|
[]struct{ k, v string }{},
|
|
map[string]string{
|
|
"Content-Type": constants.BinaryMediaType,
|
|
"Content-Length": "100",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
NewBlobUploadFn: func(repo string) (string, error) {
|
|
return "", ErrUnexpectedError
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusInternalServerError)
|
|
})
|
|
|
|
Convey("GetBlobUpload", func() {
|
|
testGetBlobUpload := func(
|
|
query []struct{ k, v string },
|
|
headers map[string]string,
|
|
vars map[string]string,
|
|
ism *mocks.MockedImageStore,
|
|
) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodGet, baseURL, nil)
|
|
request = mux.SetURLVars(request, vars)
|
|
|
|
q := request.URL.Query()
|
|
for _, qe := range query {
|
|
q.Add(qe.k, qe.v)
|
|
}
|
|
request.URL.RawQuery = q.Encode()
|
|
|
|
for k, v := range headers {
|
|
request.Header.Add(k, v)
|
|
}
|
|
|
|
response := httptest.NewRecorder()
|
|
|
|
rthdlr.GetBlobUpload(response, request)
|
|
|
|
resp := response.Result()
|
|
defer resp.Body.Close()
|
|
|
|
return resp.StatusCode
|
|
}
|
|
|
|
// ErrBadUploadRange
|
|
statusCode := testGetBlobUpload(
|
|
[]struct{ k, v string }{},
|
|
map[string]string{},
|
|
map[string]string{
|
|
"name": "test",
|
|
"session_id": "1234",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
GetBlobUploadFn: func(repo, uuid string) (int64, error) {
|
|
return 0, zerr.ErrBadUploadRange
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusBadRequest)
|
|
|
|
// ErrBadBlobDigest
|
|
statusCode = testGetBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"mount", "1234"},
|
|
},
|
|
map[string]string{},
|
|
map[string]string{
|
|
"name": "test",
|
|
"session_id": "1234",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
GetBlobUploadFn: func(repo, uuid string) (int64, error) {
|
|
return 0, zerr.ErrBadBlobDigest
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusBadRequest)
|
|
|
|
// ErrRepoNotFound
|
|
statusCode = testGetBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"mount", "1234"},
|
|
},
|
|
map[string]string{},
|
|
map[string]string{
|
|
"name": "test",
|
|
"session_id": "1234",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
GetBlobUploadFn: func(repo, uuid string) (int64, error) {
|
|
return 0, zerr.ErrRepoNotFound
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusNotFound)
|
|
|
|
// ErrUploadNotFound
|
|
statusCode = testGetBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"mount", "1234"},
|
|
},
|
|
map[string]string{},
|
|
map[string]string{
|
|
"name": "test",
|
|
"session_id": "1234",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
GetBlobUploadFn: func(repo, uuid string) (int64, error) {
|
|
return 0, zerr.ErrUploadNotFound
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusNotFound)
|
|
|
|
// ErrUploadNotFound
|
|
statusCode = testGetBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"mount", "1234"},
|
|
},
|
|
map[string]string{},
|
|
map[string]string{
|
|
"name": "test",
|
|
"session_id": "1234",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
GetBlobUploadFn: func(repo, uuid string) (int64, error) {
|
|
return 0, ErrUnexpectedError
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusInternalServerError)
|
|
})
|
|
|
|
Convey("PatchBlobUpload", func() {
|
|
testPatchBlobUpload := func(
|
|
query []struct{ k, v string },
|
|
headers map[string]string,
|
|
vars map[string]string,
|
|
ism *mocks.MockedImageStore,
|
|
) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodPatch, baseURL, nil)
|
|
|
|
request = mux.SetURLVars(request, vars)
|
|
|
|
q := request.URL.Query()
|
|
for _, qe := range query {
|
|
q.Add(qe.k, qe.v)
|
|
}
|
|
request.URL.RawQuery = q.Encode()
|
|
|
|
for k, v := range headers {
|
|
request.Header.Add(k, v)
|
|
}
|
|
|
|
response := httptest.NewRecorder()
|
|
|
|
rthdlr.PatchBlobUpload(response, request)
|
|
|
|
resp := response.Result()
|
|
defer resp.Body.Close()
|
|
|
|
return resp.StatusCode
|
|
}
|
|
|
|
status := testPatchBlobUpload(
|
|
[]struct{ k, v string }{},
|
|
map[string]string{
|
|
"Content-Length": "abc",
|
|
"Content-Range": "abc",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{},
|
|
)
|
|
So(status, ShouldEqual, http.StatusBadRequest)
|
|
|
|
status = testPatchBlobUpload(
|
|
[]struct{ k, v string }{},
|
|
map[string]string{
|
|
"Content-Length": "100",
|
|
"Content-Range": "1-50",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{},
|
|
)
|
|
So(status, ShouldEqual, http.StatusRequestedRangeNotSatisfiable)
|
|
|
|
status = testPatchBlobUpload(
|
|
[]struct{ k, v string }{},
|
|
map[string]string{
|
|
"Content-Length": "100",
|
|
"Content-Range": "1-100",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
PutBlobChunkFn: func(repo, uuid string, from, to int64, body io.Reader) (int64, error) {
|
|
return 100, zerr.ErrRepoNotFound
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusNotFound)
|
|
|
|
status = testPatchBlobUpload(
|
|
[]struct{ k, v string }{},
|
|
map[string]string{
|
|
"Content-Length": "100",
|
|
"Content-Range": "1-100",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
PutBlobChunkFn: func(repo, uuid string, from, to int64, body io.Reader) (int64, error) {
|
|
return 100, zerr.ErrUploadNotFound
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusNotFound)
|
|
|
|
status = testPatchBlobUpload(
|
|
[]struct{ k, v string }{},
|
|
map[string]string{
|
|
"Content-Length": "100",
|
|
"Content-Range": "1-100",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
PutBlobChunkFn: func(repo, uuid string, from, to int64, body io.Reader) (int64, error) {
|
|
return 100, ErrUnexpectedError
|
|
},
|
|
DeleteBlobUploadFn: func(repo, uuid string) error {
|
|
return ErrUnexpectedError
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusInternalServerError)
|
|
})
|
|
|
|
Convey("UpdateBlobUpload", func() {
|
|
testUpdateBlobUpload := func(
|
|
query []struct{ k, v string },
|
|
headers map[string]string,
|
|
vars map[string]string,
|
|
ism *mocks.MockedImageStore,
|
|
) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodPatch, baseURL, nil)
|
|
|
|
request = mux.SetURLVars(request, vars)
|
|
|
|
q := request.URL.Query()
|
|
for _, qe := range query {
|
|
q.Add(qe.k, qe.v)
|
|
}
|
|
request.URL.RawQuery = q.Encode()
|
|
|
|
for k, v := range headers {
|
|
request.Header.Add(k, v)
|
|
}
|
|
|
|
response := httptest.NewRecorder()
|
|
|
|
rthdlr.UpdateBlobUpload(response, request)
|
|
|
|
resp := response.Result()
|
|
defer resp.Body.Close()
|
|
|
|
return resp.StatusCode
|
|
}
|
|
|
|
status := testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", test.GetTestBlobDigest("zot-cve-test", "layer").String()},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "",
|
|
"Content-Range": "",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{},
|
|
)
|
|
So(status, ShouldEqual, http.StatusBadRequest)
|
|
|
|
status = testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", test.GetTestBlobDigest("zot-cve-test", "layer").String()},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "100",
|
|
"Content-Range": "badRange",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{},
|
|
)
|
|
So(status, ShouldEqual, http.StatusRequestedRangeNotSatisfiable)
|
|
|
|
status = testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", test.GetTestBlobDigest("zot-cve-test", "layer").String()},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "100",
|
|
"Content-Range": "1-100",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
PutBlobChunkFn: func(repo, uuid string, from, to int64, body io.Reader) (int64, error) {
|
|
return 0, zerr.ErrBadUploadRange
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusBadRequest)
|
|
|
|
status = testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", test.GetTestBlobDigest("zot-cve-test", "layer").String()},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "100",
|
|
"Content-Range": "1-100",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
PutBlobChunkFn: func(repo, uuid string, from, to int64, body io.Reader) (int64, error) {
|
|
return 0, zerr.ErrRepoNotFound
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusNotFound)
|
|
|
|
status = testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", test.GetTestBlobDigest("zot-cve-test", "layer").String()},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "100",
|
|
"Content-Range": "1-100",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
PutBlobChunkFn: func(repo, uuid string, from, to int64, body io.Reader) (int64, error) {
|
|
return 0, zerr.ErrUploadNotFound
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusNotFound)
|
|
|
|
status = testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", test.GetTestBlobDigest("zot-cve-test", "layer").String()},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "100",
|
|
"Content-Range": "1-100",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
PutBlobChunkFn: func(repo, uuid string, from, to int64, body io.Reader) (int64, error) {
|
|
return 0, ErrUnexpectedError
|
|
},
|
|
DeleteBlobUploadFn: func(repo, uuid string) error {
|
|
return ErrUnexpectedError
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusInternalServerError)
|
|
|
|
status = testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", test.GetTestBlobDigest("zot-cve-test", "layer").String()},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "0",
|
|
"Content-Range": "",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
FinishBlobUploadFn: func(repo, uuid string, body io.Reader, digest godigest.Digest) error {
|
|
return zerr.ErrBadBlobDigest
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusBadRequest)
|
|
|
|
status = testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", test.GetTestBlobDigest("zot-cve-test", "layer").String()},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "0",
|
|
"Content-Range": "",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
FinishBlobUploadFn: func(repo, uuid string, body io.Reader, digest godigest.Digest) error {
|
|
return zerr.ErrBadUploadRange
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusBadRequest)
|
|
|
|
status = testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", test.GetTestBlobDigest("zot-cve-test", "layer").String()},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "0",
|
|
"Content-Range": "",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
FinishBlobUploadFn: func(repo, uuid string, body io.Reader, digest godigest.Digest) error {
|
|
return zerr.ErrRepoNotFound
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusNotFound)
|
|
|
|
status = testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", test.GetTestBlobDigest("zot-cve-test", "layer").String()},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "0",
|
|
"Content-Range": "",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
FinishBlobUploadFn: func(repo, uuid string, body io.Reader, digest godigest.Digest) error {
|
|
return zerr.ErrUploadNotFound
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusNotFound)
|
|
|
|
status = testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", test.GetTestBlobDigest("zot-cve-test", "layer").String()},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "0",
|
|
"Content-Range": "",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
FinishBlobUploadFn: func(repo, uuid string, body io.Reader, digest godigest.Digest) error {
|
|
return ErrUnexpectedError
|
|
},
|
|
DeleteBlobUploadFn: func(repo, uuid string) error {
|
|
return ErrUnexpectedError
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusInternalServerError)
|
|
})
|
|
|
|
Convey("DeleteBlobUpload", func() {
|
|
testDeleteBlobUpload := func(
|
|
query []struct{ k, v string },
|
|
headers map[string]string,
|
|
vars map[string]string,
|
|
ism *mocks.MockedImageStore,
|
|
) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodPatch, baseURL, nil)
|
|
|
|
request = mux.SetURLVars(request, vars)
|
|
|
|
q := request.URL.Query()
|
|
for _, qe := range query {
|
|
q.Add(qe.k, qe.v)
|
|
}
|
|
request.URL.RawQuery = q.Encode()
|
|
|
|
for k, v := range headers {
|
|
request.Header.Add(k, v)
|
|
}
|
|
|
|
response := httptest.NewRecorder()
|
|
|
|
rthdlr.DeleteBlobUpload(response, request)
|
|
|
|
resp := response.Result()
|
|
defer resp.Body.Close()
|
|
|
|
return resp.StatusCode
|
|
}
|
|
|
|
status := testDeleteBlobUpload(
|
|
[]struct{ k, v string }{},
|
|
map[string]string{},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
DeleteBlobUploadFn: func(repo, uuid string) error {
|
|
return zerr.ErrRepoNotFound
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusNotFound)
|
|
|
|
status = testDeleteBlobUpload(
|
|
[]struct{ k, v string }{},
|
|
map[string]string{},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
DeleteBlobUploadFn: func(repo, uuid string) error {
|
|
return zerr.ErrUploadNotFound
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusNotFound)
|
|
|
|
status = testDeleteBlobUpload(
|
|
[]struct{ k, v string }{},
|
|
map[string]string{},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
DeleteBlobUploadFn: func(repo, uuid string) error {
|
|
return ErrUnexpectedError
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusInternalServerError)
|
|
})
|
|
|
|
Convey("ListRepositories", func() {
|
|
testListRepositoriesWithSubstores := func(
|
|
query []struct{ k, v string },
|
|
headers map[string]string,
|
|
vars map[string]string,
|
|
ism *mocks.MockedImageStore,
|
|
) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
ctlr.StoreController.SubStore = map[string]storage.ImageStore{
|
|
"test": &mocks.MockedImageStore{
|
|
GetRepositoriesFn: func() ([]string, error) {
|
|
return []string{}, ErrUnexpectedError
|
|
},
|
|
},
|
|
}
|
|
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodGet, baseURL, nil)
|
|
|
|
request = mux.SetURLVars(request, vars)
|
|
|
|
q := request.URL.Query()
|
|
for _, qe := range query {
|
|
q.Add(qe.k, qe.v)
|
|
}
|
|
request.URL.RawQuery = q.Encode()
|
|
|
|
for k, v := range headers {
|
|
request.Header.Add(k, v)
|
|
}
|
|
|
|
response := httptest.NewRecorder()
|
|
|
|
rthdlr.ListRepositories(response, request)
|
|
|
|
resp := response.Result()
|
|
defer resp.Body.Close()
|
|
|
|
return resp.StatusCode
|
|
}
|
|
|
|
testListRepositories := func(
|
|
query []struct{ k, v string },
|
|
headers map[string]string,
|
|
vars map[string]string,
|
|
ism *mocks.MockedImageStore,
|
|
) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
ctlr.StoreController.SubStore = map[string]storage.ImageStore{}
|
|
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodPatch, baseURL, nil)
|
|
|
|
request = mux.SetURLVars(request, vars)
|
|
|
|
q := request.URL.Query()
|
|
for _, qe := range query {
|
|
q.Add(qe.k, qe.v)
|
|
}
|
|
request.URL.RawQuery = q.Encode()
|
|
|
|
for k, v := range headers {
|
|
request.Header.Add(k, v)
|
|
}
|
|
|
|
response := httptest.NewRecorder()
|
|
|
|
rthdlr.ListRepositories(response, request)
|
|
|
|
resp := response.Result()
|
|
defer resp.Body.Close()
|
|
|
|
return resp.StatusCode
|
|
}
|
|
// with substores
|
|
status := testListRepositoriesWithSubstores(
|
|
[]struct{ k, v string }{},
|
|
map[string]string{},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
GetRepositoriesFn: func() ([]string, error) {
|
|
return []string{}, ErrUnexpectedError
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusInternalServerError)
|
|
|
|
status = testListRepositories(
|
|
[]struct{ k, v string }{},
|
|
map[string]string{},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
GetRepositoriesFn: func() ([]string, error) {
|
|
return []string{}, ErrUnexpectedError
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusInternalServerError)
|
|
})
|
|
|
|
Convey("ListRepositories with Authz", func() {
|
|
ctlr.StoreController.DefaultStore = &mocks.MockedImageStore{
|
|
GetRepositoriesFn: func() ([]string, error) {
|
|
return []string{"repo"}, nil
|
|
},
|
|
}
|
|
ctlr.StoreController.SubStore = map[string]storage.ImageStore{
|
|
"test1": &mocks.MockedImageStore{
|
|
GetRepositoriesFn: func() ([]string, error) {
|
|
return []string{"repo1"}, nil
|
|
},
|
|
},
|
|
"test2": &mocks.MockedImageStore{
|
|
GetRepositoriesFn: func() ([]string, error) {
|
|
return []string{"repo2"}, nil
|
|
},
|
|
},
|
|
}
|
|
|
|
// make the user an admin
|
|
// acCtx := api.NewAccessControlContext(map[string]bool{}, true)
|
|
// ctx := context.WithValue(context.Background(), "ctx", acCtx)
|
|
ctx := context.Background()
|
|
request, _ := http.NewRequestWithContext(ctx, http.MethodGet, baseURL, nil)
|
|
request = mux.SetURLVars(request, map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
})
|
|
response := httptest.NewRecorder()
|
|
|
|
rthdlr.ListRepositories(response, request)
|
|
|
|
resp := response.Result()
|
|
defer resp.Body.Close()
|
|
|
|
So(resp.StatusCode, ShouldEqual, http.StatusOK)
|
|
})
|
|
|
|
Convey("Helper functions", func() {
|
|
testUpdateBlobUpload := func(
|
|
query []struct{ k, v string },
|
|
headers map[string]string,
|
|
vars map[string]string,
|
|
ism *mocks.MockedImageStore,
|
|
) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodPatch, baseURL, nil)
|
|
|
|
request = mux.SetURLVars(request, vars)
|
|
|
|
q := request.URL.Query()
|
|
for _, qe := range query {
|
|
q.Add(qe.k, qe.v)
|
|
}
|
|
request.URL.RawQuery = q.Encode()
|
|
|
|
for k, v := range headers {
|
|
request.Header.Add(k, v)
|
|
}
|
|
|
|
response := httptest.NewRecorder()
|
|
|
|
rthdlr.UpdateBlobUpload(response, request)
|
|
|
|
resp := response.Result()
|
|
defer resp.Body.Close()
|
|
|
|
return resp.StatusCode
|
|
}
|
|
|
|
status := testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", test.GetTestBlobDigest("zot-cve-test", "layer").String()},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "0",
|
|
"Content-Range": "a-100",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
FinishBlobUploadFn: func(repo, uuid string, body io.Reader, digest godigest.Digest) error {
|
|
return zerr.ErrUploadNotFound
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusRequestedRangeNotSatisfiable)
|
|
|
|
status = testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", test.GetTestBlobDigest("zot-cve-test", "layer").String()},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "0",
|
|
"Content-Range": "20-a",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
FinishBlobUploadFn: func(repo, uuid string, body io.Reader, digest godigest.Digest) error {
|
|
return zerr.ErrUploadNotFound
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusRequestedRangeNotSatisfiable)
|
|
|
|
status = testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", test.GetTestBlobDigest("zot-cve-test", "layer").String()},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "0",
|
|
"Content-Range": "20-1",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&mocks.MockedImageStore{
|
|
FinishBlobUploadFn: func(repo, uuid string, body io.Reader, digest godigest.Digest) error {
|
|
return zerr.ErrUploadNotFound
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusRequestedRangeNotSatisfiable)
|
|
})
|
|
})
|
|
}
|