2022-04-27 01:00:20 -05:00
|
|
|
//go:build sync && scrub && metrics && search && ui_base
|
|
|
|
// +build sync,scrub,metrics,search,ui_base
|
2022-04-13 01:28:43 -05:00
|
|
|
|
|
|
|
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)
|
2022-05-09 17:30:11 -05:00
|
|
|
runGCRepoFn func(repo string)
|
2022-04-13 01:28:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2022-05-09 17:30:11 -05:00
|
|
|
func (is *MockedImageStore) RunGCRepo(repo string) {
|
|
|
|
if is != nil && is.runGCRepoFn != nil {
|
|
|
|
is.runGCRepoFn(repo)
|
2022-04-13 01:28:43 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|