mirror of
https://github.com/project-zot/zot.git
synced 2024-12-16 21:56:37 -05:00
ada21ed842
Files were added to be built whether an extension is on or off. New build tags were added for each extension, while minimal and extended disappeared. added custom binary naming depending on extensions used and changed references from binary to binary-extended added automated blackbox tests for sync, search, scrub, metrics added contributor guidelines Signed-off-by: Alex Stan <alexandrustan96@yahoo.ro>
1642 lines
43 KiB
Go
1642 lines
43 KiB
Go
//go:build sync && scrub && metrics && search && ui_base
|
|
// +build sync,scrub,metrics,search,ui_base
|
|
|
|
package api_test
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gorilla/mux"
|
|
"github.com/opencontainers/go-digest"
|
|
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
artifactspec "github.com/oras-project/artifacts-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"
|
|
"zotregistry.io/zot/pkg/storage"
|
|
"zotregistry.io/zot/pkg/test"
|
|
)
|
|
|
|
var ErrUnexpectedError = errors.New("error: unexpected error")
|
|
|
|
type MockedImageStore struct {
|
|
dirExistsFn func(d string) bool
|
|
rootDirFn func() string
|
|
initRepoFn func(name string) error
|
|
validateRepoFn func(name string) (bool, error)
|
|
getRepositoriesFn func() ([]string, error)
|
|
getImageTagsFn func(repo string) ([]string, error)
|
|
getImageManifestFn func(repo string, reference string) ([]byte, string, string, error)
|
|
putImageManifestFn func(repo string, reference string, mediaType string, body []byte) (string, error)
|
|
deleteImageManifestFn func(repo string, reference string) error
|
|
blobUploadPathFn func(repo string, uuid string) string
|
|
newBlobUploadFn func(repo string) (string, error)
|
|
getBlobUploadFn func(repo string, uuid string) (int64, error)
|
|
blobUploadInfoFn func(repo string, uuid string) (int64, error)
|
|
putBlobChunkStreamedFn func(repo string, uuid string, body io.Reader) (int64, error)
|
|
putBlobChunkFn func(repo string, uuid string, from int64, to int64, body io.Reader) (int64, error)
|
|
finishBlobUploadFn func(repo string, uuid string, body io.Reader, digest string) error
|
|
fullBlobUploadFn func(repo string, body io.Reader, digest string) (string, int64, error)
|
|
dedupeBlobFn func(src string, dstDigest digest.Digest, dst string) error
|
|
deleteBlobUploadFn func(repo string, uuid string) error
|
|
blobPathFn func(repo string, digest digest.Digest) string
|
|
checkBlobFn func(repo string, digest string) (bool, int64, error)
|
|
getBlobFn func(repo string, digest string, mediaType string) (io.Reader, int64, error)
|
|
deleteBlobFn func(repo string, digest string) error
|
|
getIndexContentFn func(repo string) ([]byte, error)
|
|
getBlobContentFn func(repo, digest string) ([]byte, error)
|
|
getReferrersFn func(repo, digest string, mediaType string) ([]artifactspec.Descriptor, error)
|
|
urlForPathFn func(path string) (string, error)
|
|
runGCRepoFn func(repo string)
|
|
}
|
|
|
|
func (is *MockedImageStore) Lock(t *time.Time) {
|
|
}
|
|
|
|
func (is *MockedImageStore) Unlock(t *time.Time) {
|
|
}
|
|
|
|
func (is *MockedImageStore) RUnlock(t *time.Time) {
|
|
}
|
|
|
|
func (is *MockedImageStore) RLock(t *time.Time) {
|
|
}
|
|
|
|
func (is *MockedImageStore) DirExists(d string) bool {
|
|
if is != nil && is.dirExistsFn != nil {
|
|
return is.dirExistsFn(d)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (is *MockedImageStore) RootDir() string {
|
|
if is != nil && is.rootDirFn != nil {
|
|
return is.rootDirFn()
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
func (is *MockedImageStore) InitRepo(name string) error {
|
|
if is != nil && is.initRepoFn != nil {
|
|
return is.initRepoFn(name)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (is *MockedImageStore) ValidateRepo(name string) (bool, error) {
|
|
if is != nil && is.validateRepoFn != nil {
|
|
return is.validateRepoFn(name)
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
func (is *MockedImageStore) GetRepositories() ([]string, error) {
|
|
if is != nil && is.getRepositoriesFn != nil {
|
|
return is.getRepositoriesFn()
|
|
}
|
|
|
|
return []string{}, nil
|
|
}
|
|
|
|
func (is *MockedImageStore) GetImageManifest(repo string, reference string) ([]byte, string, string, error) {
|
|
if is != nil && is.getImageManifestFn != nil {
|
|
return is.getImageManifestFn(repo, reference)
|
|
}
|
|
|
|
return []byte{}, "", "", nil
|
|
}
|
|
|
|
func (is *MockedImageStore) PutImageManifest(
|
|
repo string,
|
|
reference string,
|
|
mediaType string,
|
|
body []byte,
|
|
) (string, error) {
|
|
if is != nil && is.putImageManifestFn != nil {
|
|
return is.putImageManifestFn(repo, reference, mediaType, body)
|
|
}
|
|
|
|
return "", nil
|
|
}
|
|
|
|
func (is *MockedImageStore) GetImageTags(name string) ([]string, error) {
|
|
if is != nil && is.getImageTagsFn != nil {
|
|
return is.getImageTagsFn(name)
|
|
}
|
|
|
|
return []string{}, nil
|
|
}
|
|
|
|
func (is *MockedImageStore) DeleteImageManifest(name string, reference string) error {
|
|
if is != nil && is.deleteImageManifestFn != nil {
|
|
return is.deleteImageManifestFn(name, reference)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (is *MockedImageStore) NewBlobUpload(repo string) (string, error) {
|
|
if is != nil && is.newBlobUploadFn != nil {
|
|
return is.newBlobUploadFn(repo)
|
|
}
|
|
|
|
return "", nil
|
|
}
|
|
|
|
func (is *MockedImageStore) GetBlobUpload(repo string, uuid string) (int64, error) {
|
|
if is != nil && is.getBlobUploadFn != nil {
|
|
return is.getBlobUploadFn(repo, uuid)
|
|
}
|
|
|
|
return 0, nil
|
|
}
|
|
|
|
func (is *MockedImageStore) BlobUploadInfo(repo string, uuid string) (int64, error) {
|
|
if is != nil && is.blobUploadInfoFn != nil {
|
|
return is.blobUploadInfoFn(repo, uuid)
|
|
}
|
|
|
|
return 0, nil
|
|
}
|
|
|
|
func (is *MockedImageStore) BlobUploadPath(repo string, uuid string) string {
|
|
if is != nil && is.blobUploadPathFn != nil {
|
|
return is.blobUploadPathFn(repo, uuid)
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
func (is *MockedImageStore) PutBlobChunkStreamed(repo string, uuid string, body io.Reader) (int64, error) {
|
|
if is != nil && is.putBlobChunkStreamedFn != nil {
|
|
return is.putBlobChunkStreamedFn(repo, uuid, body)
|
|
}
|
|
|
|
return 0, nil
|
|
}
|
|
|
|
func (is *MockedImageStore) PutBlobChunk(
|
|
repo string,
|
|
uuid string,
|
|
from int64,
|
|
to int64,
|
|
body io.Reader,
|
|
) (int64, error) {
|
|
if is != nil && is.putBlobChunkFn != nil {
|
|
return is.putBlobChunkFn(repo, uuid, from, to, body)
|
|
}
|
|
|
|
return 0, nil
|
|
}
|
|
|
|
func (is *MockedImageStore) FinishBlobUpload(repo string, uuid string, body io.Reader, digest string) error {
|
|
if is != nil && is.finishBlobUploadFn != nil {
|
|
return is.finishBlobUploadFn(repo, uuid, body, digest)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (is *MockedImageStore) FullBlobUpload(repo string, body io.Reader, digest string) (string, int64, error) {
|
|
if is != nil && is.fullBlobUploadFn != nil {
|
|
return is.fullBlobUploadFn(repo, body, digest)
|
|
}
|
|
|
|
return "", 0, nil
|
|
}
|
|
|
|
func (is *MockedImageStore) DedupeBlob(src string, dstDigest digest.Digest, dst string) error {
|
|
if is != nil && is.dedupeBlobFn != nil {
|
|
return is.dedupeBlobFn(src, dstDigest, dst)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (is *MockedImageStore) DeleteBlob(repo string, digest string) error {
|
|
if is != nil && is.deleteBlobFn != nil {
|
|
return is.deleteBlobFn(repo, digest)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (is *MockedImageStore) BlobPath(repo string, digest digest.Digest) string {
|
|
if is != nil && is.blobPathFn != nil {
|
|
return is.blobPathFn(repo, digest)
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
func (is *MockedImageStore) CheckBlob(repo string, digest string) (bool, int64, error) {
|
|
if is != nil && is.checkBlobFn != nil {
|
|
return is.checkBlobFn(repo, digest)
|
|
}
|
|
|
|
return true, 0, nil
|
|
}
|
|
|
|
func (is *MockedImageStore) GetBlob(repo string, digest string, mediaType string) (io.Reader, int64, error) {
|
|
if is != nil && is.getBlobFn != nil {
|
|
return is.getBlobFn(repo, digest, mediaType)
|
|
}
|
|
|
|
return &io.LimitedReader{}, 0, nil
|
|
}
|
|
|
|
func (is *MockedImageStore) DeleteBlobUpload(repo string, digest string) error {
|
|
if is != nil && is.deleteBlobUploadFn != nil {
|
|
return is.deleteBlobUploadFn(repo, digest)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (is *MockedImageStore) GetIndexContent(repo string) ([]byte, error) {
|
|
if is != nil && is.getIndexContentFn != nil {
|
|
return is.getIndexContentFn(repo)
|
|
}
|
|
|
|
return []byte{}, nil
|
|
}
|
|
|
|
func (is *MockedImageStore) GetBlobContent(repo string, digest string) ([]byte, error) {
|
|
if is != nil && is.getBlobContentFn != nil {
|
|
return is.getBlobContentFn(repo, digest)
|
|
}
|
|
|
|
return []byte{}, nil
|
|
}
|
|
|
|
func (is *MockedImageStore) GetReferrers(
|
|
repo string,
|
|
digest string,
|
|
mediaType string,
|
|
) ([]artifactspec.Descriptor, error) {
|
|
if is != nil && is.getReferrersFn != nil {
|
|
return is.getReferrersFn(repo, digest, mediaType)
|
|
}
|
|
|
|
return []artifactspec.Descriptor{}, nil
|
|
}
|
|
|
|
func (is *MockedImageStore) URLForPath(path string) (string, error) {
|
|
if is != nil && is.urlForPathFn != nil {
|
|
return is.urlForPathFn(path)
|
|
}
|
|
|
|
return "", nil
|
|
}
|
|
|
|
func (is *MockedImageStore) RunGCRepo(repo string) {
|
|
if is != nil && is.runGCRepoFn != nil {
|
|
is.runGCRepoFn(repo)
|
|
}
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
go startServer(ctlr)
|
|
defer stopServer(ctlr)
|
|
test.WaitTillServerReady(baseURL)
|
|
|
|
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("Get manifest", func() {
|
|
// overwrite controller storage
|
|
ctlr.StoreController.DefaultStore = &MockedImageStore{
|
|
getImageManifestFn: func(repo string, reference string) ([]byte, string, string, error) {
|
|
return []byte{}, "", "", zerr.ErrRepoBadVersion
|
|
},
|
|
}
|
|
|
|
request, _ := http.NewRequestWithContext(context.TODO(), "GET", 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 *MockedImageStore) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
str := []byte("test")
|
|
request, _ := http.NewRequestWithContext(context.TODO(), "PUT", 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",
|
|
},
|
|
&MockedImageStore{
|
|
putImageManifestFn: func(repo, reference, mediaType string, body []byte) (string, error) {
|
|
return "", zerr.ErrRepoNotFound
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusNotFound)
|
|
// ErrManifestNotFound
|
|
statusCode = testUpdateManifest(
|
|
map[string]string{
|
|
"name": "test",
|
|
"reference": "reference",
|
|
},
|
|
|
|
&MockedImageStore{
|
|
putImageManifestFn: func(repo, reference, mediaType string, body []byte) (string, error) {
|
|
return "", zerr.ErrManifestNotFound
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusNotFound)
|
|
// ErrBadManifest
|
|
statusCode = testUpdateManifest(
|
|
map[string]string{
|
|
"name": "test",
|
|
"reference": "reference",
|
|
},
|
|
&MockedImageStore{
|
|
putImageManifestFn: func(repo, reference, mediaType string, body []byte) (string, error) {
|
|
return "", zerr.ErrBadManifest
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusBadRequest)
|
|
// ErrBlobNotFound
|
|
statusCode = testUpdateManifest(
|
|
map[string]string{
|
|
"name": "test",
|
|
"reference": "reference",
|
|
},
|
|
&MockedImageStore{
|
|
putImageManifestFn: func(repo, reference, mediaType string, body []byte) (string, error) {
|
|
return "", zerr.ErrBlobNotFound
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusBadRequest)
|
|
|
|
// ErrRepoBadVersion
|
|
statusCode = testUpdateManifest(
|
|
map[string]string{
|
|
"name": "test",
|
|
"reference": "reference",
|
|
},
|
|
&MockedImageStore{
|
|
putImageManifestFn: func(repo, reference, mediaType string, body []byte) (string, error) {
|
|
return "", zerr.ErrRepoBadVersion
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusInternalServerError)
|
|
})
|
|
|
|
Convey("DeleteManifest", func() {
|
|
testDeleteManifest := func(headers map[string]string, urlVars map[string]string, ism *MockedImageStore) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
request, _ := http.NewRequestWithContext(context.Background(), "DELETE", 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",
|
|
},
|
|
&MockedImageStore{
|
|
deleteImageManifestFn: func(repo, reference string) error {
|
|
return zerr.ErrRepoNotFound
|
|
},
|
|
},
|
|
)
|
|
So(statusCode, ShouldEqual, http.StatusBadRequest)
|
|
|
|
// ErrManifestNotFound
|
|
statusCode = testDeleteManifest(
|
|
map[string]string{},
|
|
map[string]string{
|
|
"name": "ErrManifestNotFound",
|
|
"reference": "reference",
|
|
},
|
|
&MockedImageStore{
|
|
deleteImageManifestFn: func(repo, reference string) error {
|
|
return zerr.ErrManifestNotFound
|
|
},
|
|
},
|
|
)
|
|
So(statusCode, ShouldEqual, http.StatusNotFound)
|
|
|
|
// ErrUnexpectedError
|
|
statusCode = testDeleteManifest(
|
|
map[string]string{},
|
|
map[string]string{
|
|
"name": "ErrUnexpectedError",
|
|
"reference": "reference",
|
|
},
|
|
&MockedImageStore{
|
|
deleteImageManifestFn: func(repo, reference string) error {
|
|
return ErrUnexpectedError
|
|
},
|
|
},
|
|
)
|
|
So(statusCode, ShouldEqual, http.StatusInternalServerError)
|
|
|
|
// ErrBadManifest
|
|
statusCode = testDeleteManifest(
|
|
map[string]string{},
|
|
map[string]string{
|
|
"name": "ErrBadManifest",
|
|
"reference": "reference",
|
|
},
|
|
&MockedImageStore{
|
|
deleteImageManifestFn: func(repo, reference string) error {
|
|
return zerr.ErrBadManifest
|
|
},
|
|
},
|
|
)
|
|
So(statusCode, ShouldEqual, http.StatusBadRequest)
|
|
})
|
|
|
|
Convey("DeleteBlob", func() {
|
|
testDeleteBlob := func(urlVars map[string]string, ism *MockedImageStore) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
request, _ := http.NewRequestWithContext(context.TODO(), "DELETE", 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": "sha256:7a0437f04f83f084b7ed68ad9c4a4947e12fc4e1b006b38129bac89114ec3621",
|
|
},
|
|
&MockedImageStore{
|
|
deleteBlobFn: func(repo, digest string) error {
|
|
return ErrUnexpectedError
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusInternalServerError)
|
|
|
|
statusCode = testDeleteBlob(
|
|
map[string]string{
|
|
"name": "ErrBadBlobDigest",
|
|
"digest": "sha256:7b8437f04f83f084b7ed68ad8c4a4947e12fc4e1b006b38129bac89114ec3621",
|
|
},
|
|
&MockedImageStore{
|
|
deleteBlobFn: func(repo, digest string) error {
|
|
return zerr.ErrBadBlobDigest
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusBadRequest)
|
|
|
|
// ErrBlobNotFound
|
|
statusCode = testDeleteBlob(
|
|
map[string]string{
|
|
"name": "ErrBlobNotFound",
|
|
"digest": "sha256:7a0437f04f83f084b7ed68ad9c4a4947e12fc4e1b006b38129bac89114ec3621",
|
|
},
|
|
&MockedImageStore{
|
|
deleteBlobFn: func(repo, digest string) error {
|
|
return zerr.ErrBlobNotFound
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusNotFound)
|
|
|
|
// ErrRepoNotFound
|
|
statusCode = testDeleteBlob(
|
|
map[string]string{
|
|
"name": "ErrRepoNotFound",
|
|
"digest": "sha256:7a0437f04f83f084b7ed68ad9c4a4947e12fc4e1b006b38129bac89114ec3621",
|
|
},
|
|
&MockedImageStore{
|
|
deleteBlobFn: func(repo, digest string) error {
|
|
return zerr.ErrRepoNotFound
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusNotFound)
|
|
})
|
|
|
|
// Check Blob
|
|
Convey("CheckBlob", func() {
|
|
testCheckBlob := func(urlVars map[string]string, ism *MockedImageStore) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
request, _ := http.NewRequestWithContext(context.TODO(), "HEAD", 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",
|
|
},
|
|
&MockedImageStore{
|
|
checkBlobFn: func(repo, digest string) (bool, int64, error) {
|
|
return true, 0, zerr.ErrBadBlobDigest
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusBadRequest)
|
|
|
|
// ErrRepoNotFound
|
|
statusCode = testCheckBlob(
|
|
map[string]string{
|
|
"name": "ErrRepoNotFound",
|
|
"digest": "1234",
|
|
},
|
|
&MockedImageStore{
|
|
checkBlobFn: func(repo, digest string) (bool, int64, error) {
|
|
return true, 0, zerr.ErrRepoNotFound
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusNotFound)
|
|
|
|
// ErrBlobNotFound
|
|
statusCode = testCheckBlob(
|
|
map[string]string{
|
|
"name": "ErrBlobNotFound",
|
|
"digest": "1234",
|
|
},
|
|
&MockedImageStore{
|
|
checkBlobFn: func(repo, digest string) (bool, int64, error) {
|
|
return true, 0, zerr.ErrBlobNotFound
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusNotFound)
|
|
|
|
// ErrUnexpectedError
|
|
statusCode = testCheckBlob(
|
|
map[string]string{
|
|
"name": "ErrUnexpectedError",
|
|
"digest": "1234",
|
|
},
|
|
&MockedImageStore{
|
|
checkBlobFn: func(repo, digest string) (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",
|
|
},
|
|
&MockedImageStore{
|
|
checkBlobFn: func(repo, digest string) (bool, int64, error) {
|
|
return false, 0, nil
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusNotFound)
|
|
})
|
|
|
|
Convey("GetBlob", func() {
|
|
testGetBlob := func(urlVars map[string]string, ism *MockedImageStore) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
request, _ := http.NewRequestWithContext(context.TODO(), "GET", 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": "sha256:7a0437f04f83f084b7ed68ad9c4a4947e12fc4e1b006b38129bac89114ec3621",
|
|
},
|
|
&MockedImageStore{
|
|
getBlobFn: func(repo, digest, mediaType string) (io.Reader, int64, error) {
|
|
return bytes.NewBuffer([]byte("")), 0, zerr.ErrRepoNotFound
|
|
},
|
|
})
|
|
So(statusCode, ShouldEqual, http.StatusNotFound)
|
|
|
|
// ErrRepoNotFound
|
|
statusCode = testGetBlob(
|
|
map[string]string{
|
|
"name": "ErrRepoNotFound",
|
|
"digest": "sha256:7a0437f04f83f084b7ed68ad9c4a4947e12fc4e1b006b38129bac89114ec3621",
|
|
},
|
|
&MockedImageStore{
|
|
getBlobFn: func(repo, digest, mediaType string) (io.Reader, int64, error) {
|
|
return 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 *MockedImageStore,
|
|
) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
request, _ := http.NewRequestWithContext(context.TODO(), "POST", 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{},
|
|
&MockedImageStore{
|
|
newBlobUploadFn: func(repo string) (string, error) {
|
|
return "", zerr.ErrRepoNotFound
|
|
},
|
|
checkBlobFn: func(repo, digest string) (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{},
|
|
&MockedImageStore{
|
|
newBlobUploadFn: func(repo string) (string, error) {
|
|
return "", zerr.ErrRepoNotFound
|
|
},
|
|
checkBlobFn: func(repo, digest string) (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",
|
|
},
|
|
&MockedImageStore{
|
|
newBlobUploadFn: func(repo string) (string, error) {
|
|
return "", zerr.ErrRepoNotFound
|
|
},
|
|
checkBlobFn: func(repo, digest string) (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",
|
|
},
|
|
&MockedImageStore{
|
|
fullBlobUploadFn: func(repo string, body io.Reader, digest string) (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",
|
|
},
|
|
&MockedImageStore{
|
|
fullBlobUploadFn: func(repo string, body io.Reader, digest string) (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",
|
|
},
|
|
&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",
|
|
},
|
|
&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 *MockedImageStore,
|
|
) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
request, _ := http.NewRequestWithContext(context.TODO(), "GET", 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",
|
|
},
|
|
&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",
|
|
},
|
|
&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",
|
|
},
|
|
&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",
|
|
},
|
|
&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",
|
|
},
|
|
&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 *MockedImageStore,
|
|
) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
request, _ := http.NewRequestWithContext(context.TODO(), "PATCH", 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",
|
|
},
|
|
&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",
|
|
},
|
|
&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",
|
|
},
|
|
&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",
|
|
},
|
|
&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",
|
|
},
|
|
&MockedImageStore{
|
|
putBlobChunkFn: func(repo, uuid string, from, to int64, body io.Reader) (int64, error) {
|
|
return 100, 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 *MockedImageStore,
|
|
) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
request, _ := http.NewRequestWithContext(context.TODO(), "PATCH", 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", "sha256:7a0437f04f83f084b7ed68ad9c4a4947e12fc4e1b006b38129bac89114ec3621"},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "",
|
|
"Content-Range": "",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&MockedImageStore{},
|
|
)
|
|
So(status, ShouldEqual, http.StatusBadRequest)
|
|
|
|
status = testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", "sha256:7a0437f04f83f084b7ed68ad9c4a4947e12fc4e1b006b38129bac89114ec3621"},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "100",
|
|
"Content-Range": "badRange",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&MockedImageStore{},
|
|
)
|
|
So(status, ShouldEqual, http.StatusRequestedRangeNotSatisfiable)
|
|
|
|
status = testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", "sha256:7a0437f04f83f084b7ed68ad9c4a4947e12fc4e1b006b38129bac89114ec3621"},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "100",
|
|
"Content-Range": "1-100",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&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", "sha256:7a0437f04f83f084b7ed68ad9c4a4947e12fc4e1b006b38129bac89114ec3621"},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "100",
|
|
"Content-Range": "1-100",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&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", "sha256:7a0437f04f83f084b7ed68ad9c4a4947e12fc4e1b006b38129bac89114ec3621"},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "100",
|
|
"Content-Range": "1-100",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&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", "sha256:7a0437f04f83f084b7ed68ad9c4a4947e12fc4e1b006b38129bac89114ec3621"},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "100",
|
|
"Content-Range": "1-100",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&MockedImageStore{
|
|
putBlobChunkFn: func(repo, uuid string, from, to int64, body io.Reader) (int64, error) {
|
|
return 0, ErrUnexpectedError
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusInternalServerError)
|
|
|
|
status = testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", "sha256:7a0437f04f83f084b7ed68ad9c4a4947e12fc4e1b006b38129bac89114ec3621"},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "0",
|
|
"Content-Range": "",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&MockedImageStore{
|
|
finishBlobUploadFn: func(repo, uuid string, body io.Reader, digest string) error {
|
|
return zerr.ErrBadBlobDigest
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusBadRequest)
|
|
|
|
status = testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", "sha256:7a0437f04f83f084b7ed68ad9c4a4947e12fc4e1b006b38129bac89114ec3621"},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "0",
|
|
"Content-Range": "",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&MockedImageStore{
|
|
finishBlobUploadFn: func(repo, uuid string, body io.Reader, digest string) error {
|
|
return zerr.ErrBadUploadRange
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusBadRequest)
|
|
|
|
status = testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", "sha256:7a0437f04f83f084b7ed68ad9c4a4947e12fc4e1b006b38129bac89114ec3621"},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "0",
|
|
"Content-Range": "",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&MockedImageStore{
|
|
finishBlobUploadFn: func(repo, uuid string, body io.Reader, digest string) error {
|
|
return zerr.ErrRepoNotFound
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusNotFound)
|
|
|
|
status = testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", "sha256:7a0437f04f83f084b7ed68ad9c4a4947e12fc4e1b006b38129bac89114ec3621"},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "0",
|
|
"Content-Range": "",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&MockedImageStore{
|
|
finishBlobUploadFn: func(repo, uuid string, body io.Reader, digest string) error {
|
|
return zerr.ErrUploadNotFound
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusNotFound)
|
|
|
|
status = testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", "sha256:7a0437f04f83f084b7ed68ad9c4a4947e12fc4e1b006b38129bac89114ec3621"},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "0",
|
|
"Content-Range": "",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&MockedImageStore{
|
|
finishBlobUploadFn: func(repo, uuid string, body io.Reader, digest 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 *MockedImageStore,
|
|
) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
request, _ := http.NewRequestWithContext(context.TODO(), "PATCH", 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",
|
|
},
|
|
&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",
|
|
},
|
|
&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",
|
|
},
|
|
&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 *MockedImageStore,
|
|
) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
ctlr.StoreController.SubStore = map[string]storage.ImageStore{
|
|
"test": &MockedImageStore{
|
|
getRepositoriesFn: func() ([]string, error) {
|
|
return []string{}, ErrUnexpectedError
|
|
},
|
|
},
|
|
}
|
|
request, _ := http.NewRequestWithContext(context.TODO(), "GET", 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 *MockedImageStore,
|
|
) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
ctlr.StoreController.SubStore = map[string]storage.ImageStore{}
|
|
request, _ := http.NewRequestWithContext(context.TODO(), "PATCH", 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",
|
|
},
|
|
&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",
|
|
},
|
|
&MockedImageStore{
|
|
getRepositoriesFn: func() ([]string, error) {
|
|
return []string{}, ErrUnexpectedError
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusInternalServerError)
|
|
})
|
|
|
|
Convey("ListRepositories with Authz", func() {
|
|
ctlr.StoreController.DefaultStore = &MockedImageStore{
|
|
getRepositoriesFn: func() ([]string, error) {
|
|
return []string{"repo"}, nil
|
|
},
|
|
}
|
|
ctlr.StoreController.SubStore = map[string]storage.ImageStore{
|
|
"test1": &MockedImageStore{
|
|
getRepositoriesFn: func() ([]string, error) {
|
|
return []string{"repo1"}, nil
|
|
},
|
|
},
|
|
"test2": &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, "GET", 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 *MockedImageStore,
|
|
) int {
|
|
ctlr.StoreController.DefaultStore = ism
|
|
request, _ := http.NewRequestWithContext(context.TODO(), "PATCH", 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", "sha256:7a0437f04f83f084b7ed68ad9c4a4947e12fc4e1b006b38129bac89114ec3621"},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "0",
|
|
"Content-Range": "a-100",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&MockedImageStore{
|
|
finishBlobUploadFn: func(repo, uuid string, body io.Reader, digest string) error {
|
|
return zerr.ErrUploadNotFound
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusRequestedRangeNotSatisfiable)
|
|
|
|
status = testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", "sha256:7a0437f04f83f084b7ed68ad9c4a4947e12fc4e1b006b38129bac89114ec3621"},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "0",
|
|
"Content-Range": "20-a",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&MockedImageStore{
|
|
finishBlobUploadFn: func(repo, uuid string, body io.Reader, digest string) error {
|
|
return zerr.ErrUploadNotFound
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusRequestedRangeNotSatisfiable)
|
|
|
|
status = testUpdateBlobUpload(
|
|
[]struct{ k, v string }{
|
|
{"digest", "sha256:7a0437f04f83f084b7ed68ad9c4a4947e12fc4e1b006b38129bac89114ec3621"},
|
|
},
|
|
map[string]string{
|
|
"Content-Length": "0",
|
|
"Content-Range": "20-1",
|
|
},
|
|
map[string]string{
|
|
"name": "repo",
|
|
"session_id": "test",
|
|
},
|
|
&MockedImageStore{
|
|
finishBlobUploadFn: func(repo, uuid string, body io.Reader, digest string) error {
|
|
return zerr.ErrUploadNotFound
|
|
},
|
|
},
|
|
)
|
|
So(status, ShouldEqual, http.StatusRequestedRangeNotSatisfiable)
|
|
})
|
|
})
|
|
}
|