forked from TrueCloudLab/frostfs-s3-gw
[#185] Add tests for list multipart uploads
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
parent
8efcc957ea
commit
8898c2ec08
3 changed files with 110 additions and 16 deletions
|
@ -322,7 +322,7 @@ var errorCodes = errorCodeMap{
|
||||||
ErrInvalidMaxUploads: {
|
ErrInvalidMaxUploads: {
|
||||||
ErrCode: ErrInvalidMaxUploads,
|
ErrCode: ErrInvalidMaxUploads,
|
||||||
Code: "InvalidArgument",
|
Code: "InvalidArgument",
|
||||||
Description: "Argument max-uploads must be an integer between 0 and 2147483647",
|
Description: "Argument max-uploads must be an integer from 1 to 1000",
|
||||||
HTTPStatusCode: http.StatusBadRequest,
|
HTTPStatusCode: http.StatusBadRequest,
|
||||||
},
|
},
|
||||||
ErrInvalidMaxKeys: {
|
ErrInvalidMaxKeys: {
|
||||||
|
|
|
@ -93,6 +93,13 @@ type (
|
||||||
const (
|
const (
|
||||||
uploadIDHeaderName = "uploadId"
|
uploadIDHeaderName = "uploadId"
|
||||||
partNumberHeaderName = "partNumber"
|
partNumberHeaderName = "partNumber"
|
||||||
|
|
||||||
|
prefixQueryName = "prefix"
|
||||||
|
delimiterQueryName = "delimiter"
|
||||||
|
maxUploadsQueryName = "max-uploads"
|
||||||
|
encodingTypeQueryName = "encoding-type"
|
||||||
|
keyMarkerQueryName = "key-marker"
|
||||||
|
uploadIDMarkerQueryName = "upload-id-marker"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *handler) CreateMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
|
func (h *handler) CreateMultipartUploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -529,30 +536,27 @@ func (h *handler) ListMultipartUploadsHandler(w http.ResponseWriter, r *http.Req
|
||||||
|
|
||||||
var (
|
var (
|
||||||
queryValues = reqInfo.URL.Query()
|
queryValues = reqInfo.URL.Query()
|
||||||
delimiter = queryValues.Get("delimiter")
|
maxUploadsStr = queryValues.Get(maxUploadsQueryName)
|
||||||
prefix = queryValues.Get("prefix")
|
|
||||||
maxUploads = layer.MaxSizeUploadsList
|
maxUploads = layer.MaxSizeUploadsList
|
||||||
)
|
)
|
||||||
|
|
||||||
if queryValues.Get("max-uploads") != "" {
|
if maxUploadsStr != "" {
|
||||||
val, err := strconv.Atoi(queryValues.Get("max-uploads"))
|
val, err := strconv.Atoi(maxUploadsStr)
|
||||||
if err != nil || val < 0 {
|
if err != nil || val < 1 || val > 1000 {
|
||||||
h.logAndSendError(w, "invalid maxUploads", reqInfo, errors.GetAPIError(errors.ErrInvalidMaxUploads))
|
h.logAndSendError(w, "invalid maxUploads", reqInfo, errors.GetAPIError(errors.ErrInvalidMaxUploads))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if val < maxUploads {
|
|
||||||
maxUploads = val
|
maxUploads = val
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
p := &layer.ListMultipartUploadsParams{
|
p := &layer.ListMultipartUploadsParams{
|
||||||
Bkt: bktInfo,
|
Bkt: bktInfo,
|
||||||
Delimiter: delimiter,
|
Delimiter: queryValues.Get(delimiterQueryName),
|
||||||
EncodingType: queryValues.Get("encoding-type"),
|
EncodingType: queryValues.Get(encodingTypeQueryName),
|
||||||
KeyMarker: queryValues.Get("key-marker"),
|
KeyMarker: queryValues.Get(keyMarkerQueryName),
|
||||||
MaxUploads: maxUploads,
|
MaxUploads: maxUploads,
|
||||||
Prefix: prefix,
|
Prefix: queryValues.Get(prefixQueryName),
|
||||||
UploadIDMarker: queryValues.Get("upload-id-marker"),
|
UploadIDMarker: queryValues.Get(uploadIDMarkerQueryName),
|
||||||
}
|
}
|
||||||
|
|
||||||
list, err := h.obj.ListMultipartUploads(r.Context(), p)
|
list, err := h.obj.ListMultipartUploads(r.Context(), p)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -105,6 +106,95 @@ func TestMultipartReUploadPart(t *testing.T) {
|
||||||
equalDataSlices(t, append(data1, data2...), data)
|
equalDataSlices(t, append(data1, data2...), data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestListMultipartUploads(t *testing.T) {
|
||||||
|
hc := prepareHandlerContext(t)
|
||||||
|
|
||||||
|
bktName := "bucket-to-list-uploads"
|
||||||
|
createTestBucket(hc, bktName)
|
||||||
|
|
||||||
|
objName1 := "/my/object/name"
|
||||||
|
uploadInfo1 := createMultipartUpload(hc, bktName, objName1, map[string]string{})
|
||||||
|
objName2 := "/my/object2"
|
||||||
|
uploadInfo2 := createMultipartUpload(hc, bktName, objName2, map[string]string{})
|
||||||
|
objName3 := "/zzz/object/name3"
|
||||||
|
uploadInfo3 := createMultipartUpload(hc, bktName, objName3, map[string]string{})
|
||||||
|
|
||||||
|
t.Run("check upload key", func(t *testing.T) {
|
||||||
|
listUploads := listAllMultipartUploads(hc, bktName)
|
||||||
|
require.Len(t, listUploads.Uploads, 3)
|
||||||
|
for i, upload := range []*InitiateMultipartUploadResponse{uploadInfo1, uploadInfo2, uploadInfo3} {
|
||||||
|
require.Equal(t, upload.UploadID, listUploads.Uploads[i].UploadID)
|
||||||
|
require.Equal(t, upload.Key, listUploads.Uploads[i].Key)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("check max uploads", func(t *testing.T) {
|
||||||
|
listUploads := listMultipartUploadsBase(hc, bktName, "", "", "", "", 2)
|
||||||
|
require.Len(t, listUploads.Uploads, 2)
|
||||||
|
require.Equal(t, uploadInfo1.UploadID, listUploads.Uploads[0].UploadID)
|
||||||
|
require.Equal(t, uploadInfo2.UploadID, listUploads.Uploads[1].UploadID)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("check prefix", func(t *testing.T) {
|
||||||
|
listUploads := listMultipartUploadsBase(hc, bktName, "/my", "", "", "", -1)
|
||||||
|
require.Len(t, listUploads.Uploads, 2)
|
||||||
|
require.Equal(t, uploadInfo1.UploadID, listUploads.Uploads[0].UploadID)
|
||||||
|
require.Equal(t, uploadInfo2.UploadID, listUploads.Uploads[1].UploadID)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("check markers", func(t *testing.T) {
|
||||||
|
t.Run("check only key-marker", func(t *testing.T) {
|
||||||
|
listUploads := listMultipartUploadsBase(hc, bktName, "", "", "", objName2, -1)
|
||||||
|
require.Len(t, listUploads.Uploads, 1)
|
||||||
|
// If upload-id-marker is not specified, only the keys lexicographically greater than the specified key-marker will be included in the list.
|
||||||
|
require.Equal(t, uploadInfo3.UploadID, listUploads.Uploads[0].UploadID)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("check only upload-id-marker", func(t *testing.T) {
|
||||||
|
uploadIDMarker := uploadInfo1.UploadID
|
||||||
|
if uploadIDMarker > uploadInfo2.UploadID {
|
||||||
|
uploadIDMarker = uploadInfo2.UploadID
|
||||||
|
}
|
||||||
|
listUploads := listMultipartUploadsBase(hc, bktName, "", "", uploadIDMarker, "", -1)
|
||||||
|
// If key-marker is not specified, the upload-id-marker parameter is ignored.
|
||||||
|
require.Len(t, listUploads.Uploads, 3)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("check key-marker along with upload-id-marker", func(t *testing.T) {
|
||||||
|
uploadIDMarker := "00000000-0000-0000-0000-000000000000"
|
||||||
|
|
||||||
|
listUploads := listMultipartUploadsBase(hc, bktName, "", "", uploadIDMarker, objName3, -1)
|
||||||
|
require.Len(t, listUploads.Uploads, 1)
|
||||||
|
// If upload-id-marker is specified, any multipart uploads for a key equal to the key-marker might also be included,
|
||||||
|
// provided those multipart uploads have upload IDs lexicographically greater than the specified upload-id-marker.
|
||||||
|
require.Equal(t, uploadInfo3.UploadID, listUploads.Uploads[0].UploadID)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func listAllMultipartUploads(hc *handlerContext, bktName string) *ListMultipartUploadsResponse {
|
||||||
|
return listMultipartUploadsBase(hc, bktName, "", "", "", "", -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listMultipartUploadsBase(hc *handlerContext, bktName, prefix, delimiter, uploadIDMarker, keyMarker string, maxUploads int) *ListMultipartUploadsResponse {
|
||||||
|
query := make(url.Values)
|
||||||
|
query.Set(prefixQueryName, prefix)
|
||||||
|
query.Set(delimiterQueryName, delimiter)
|
||||||
|
query.Set(uploadIDMarkerQueryName, uploadIDMarker)
|
||||||
|
query.Set(keyMarkerQueryName, keyMarker)
|
||||||
|
if maxUploads != -1 {
|
||||||
|
query.Set(maxUploadsQueryName, strconv.Itoa(maxUploads))
|
||||||
|
}
|
||||||
|
|
||||||
|
w, r := prepareTestRequestWithQuery(hc, bktName, "", query, nil)
|
||||||
|
|
||||||
|
hc.Handler().ListMultipartUploadsHandler(w, r)
|
||||||
|
listPartsResponse := &ListMultipartUploadsResponse{}
|
||||||
|
readResponse(hc.t, w, http.StatusOK, listPartsResponse)
|
||||||
|
|
||||||
|
return listPartsResponse
|
||||||
|
}
|
||||||
|
|
||||||
func listParts(hc *handlerContext, bktName, objName string, uploadID string) *ListPartsResponse {
|
func listParts(hc *handlerContext, bktName, objName string, uploadID string) *ListPartsResponse {
|
||||||
return listPartsBase(hc, bktName, objName, false, uploadID)
|
return listPartsBase(hc, bktName, objName, false, uploadID)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue