[#207] Fix part-number-marker handling

Signed-off-by: Marina Biryukova <m.biryukova@yadro.com>
This commit is contained in:
Marina Biryukova 2023-09-15 18:08:02 +03:00
parent 16840f1256
commit 12cf29aed2
4 changed files with 50 additions and 9 deletions

View file

@ -323,6 +323,8 @@ func assertStatus(t *testing.T, w *httptest.ResponseRecorder, status int) {
func readResponse(t *testing.T, w *httptest.ResponseRecorder, status int, model interface{}) { func readResponse(t *testing.T, w *httptest.ResponseRecorder, status int, model interface{}) {
assertStatus(t, w, status) assertStatus(t, w, status)
if status == http.StatusOK {
err := xml.NewDecoder(w.Result().Body).Decode(model) err := xml.NewDecoder(w.Result().Body).Decode(model)
require.NoError(t, err) require.NoError(t, err)
} }
}

View file

@ -600,7 +600,7 @@ func (h *handler) ListPartsHandler(w http.ResponseWriter, r *http.Request) {
} }
if queryValues.Get("part-number-marker") != "" { if queryValues.Get("part-number-marker") != "" {
if partNumberMarker, err = strconv.Atoi(queryValues.Get("part-number-marker")); err != nil || partNumberMarker <= 0 { if partNumberMarker, err = strconv.Atoi(queryValues.Get("part-number-marker")); err != nil || partNumberMarker < 0 {
h.logAndSendError(w, "invalid PartNumberMarker", reqInfo, err, additional...) h.logAndSendError(w, "invalid PartNumberMarker", reqInfo, err, additional...)
return return
} }

View file

@ -16,6 +16,10 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
const (
partNumberMarkerQuery = "part-number-marker"
)
func TestPeriodicWriter(t *testing.T) { func TestPeriodicWriter(t *testing.T) {
const dur = 100 * time.Millisecond const dur = 100 * time.Millisecond
const whitespaces = 8 const whitespaces = 8
@ -80,7 +84,7 @@ func TestMultipartReUploadPart(t *testing.T) {
etag1, _ := uploadPart(hc, bktName, objName, uploadInfo.UploadID, 1, partSizeLast) etag1, _ := uploadPart(hc, bktName, objName, uploadInfo.UploadID, 1, partSizeLast)
etag2, _ := uploadPart(hc, bktName, objName, uploadInfo.UploadID, 2, partSizeFirst) etag2, _ := uploadPart(hc, bktName, objName, uploadInfo.UploadID, 2, partSizeFirst)
list := listParts(hc, bktName, objName, uploadInfo.UploadID) list := listParts(hc, bktName, objName, uploadInfo.UploadID, "0", http.StatusOK)
require.Len(t, list.Parts, 2) require.Len(t, list.Parts, 2)
require.Equal(t, etag1, list.Parts[0].ETag) require.Equal(t, etag1, list.Parts[0].ETag)
require.Equal(t, etag2, list.Parts[1].ETag) require.Equal(t, etag2, list.Parts[1].ETag)
@ -91,7 +95,7 @@ func TestMultipartReUploadPart(t *testing.T) {
etag1, data1 := uploadPart(hc, bktName, objName, uploadInfo.UploadID, 1, partSizeFirst) etag1, data1 := uploadPart(hc, bktName, objName, uploadInfo.UploadID, 1, partSizeFirst)
etag2, data2 := uploadPart(hc, bktName, objName, uploadInfo.UploadID, 2, partSizeLast) etag2, data2 := uploadPart(hc, bktName, objName, uploadInfo.UploadID, 2, partSizeLast)
list = listParts(hc, bktName, objName, uploadInfo.UploadID) list = listParts(hc, bktName, objName, uploadInfo.UploadID, "0", http.StatusOK)
require.Len(t, list.Parts, 2) require.Len(t, list.Parts, 2)
require.Equal(t, etag1, list.Parts[0].ETag) require.Equal(t, etag1, list.Parts[0].ETag)
require.Equal(t, etag2, list.Parts[1].ETag) require.Equal(t, etag2, list.Parts[1].ETag)
@ -219,6 +223,36 @@ func TestMultipartUploadSize(t *testing.T) {
}) })
} }
func TestListParts(t *testing.T) {
hc := prepareHandlerContext(t)
bktName, objName := "bucket-for-test-list-parts", "object-multipart"
_ = createTestBucket(hc, bktName)
partSize := 5 * 1024 * 1024
uploadInfo := createMultipartUpload(hc, bktName, objName, map[string]string{})
etag1, _ := uploadPart(hc, bktName, objName, uploadInfo.UploadID, 1, partSize)
etag2, _ := uploadPart(hc, bktName, objName, uploadInfo.UploadID, 2, partSize)
list := listParts(hc, bktName, objName, uploadInfo.UploadID, "0", http.StatusOK)
require.Len(t, list.Parts, 2)
require.Equal(t, etag1, list.Parts[0].ETag)
require.Equal(t, etag2, list.Parts[1].ETag)
list = listParts(hc, bktName, objName, uploadInfo.UploadID, "1", http.StatusOK)
require.Len(t, list.Parts, 1)
require.Equal(t, etag2, list.Parts[0].ETag)
list = listParts(hc, bktName, objName, uploadInfo.UploadID, "2", http.StatusOK)
require.Len(t, list.Parts, 0)
list = listParts(hc, bktName, objName, uploadInfo.UploadID, "7", http.StatusOK)
require.Len(t, list.Parts, 0)
list = listParts(hc, bktName, objName, uploadInfo.UploadID, "-1", http.StatusInternalServerError)
require.Len(t, list.Parts, 0)
}
func uploadPartCopy(hc *handlerContext, bktName, objName, uploadID string, num int, srcObj string, start, end int) *UploadPartCopyResponse { func uploadPartCopy(hc *handlerContext, bktName, objName, uploadID string, num int, srcObj string, start, end int) *UploadPartCopyResponse {
return uploadPartCopyBase(hc, bktName, objName, false, uploadID, num, srcObj, start, end) return uploadPartCopyBase(hc, bktName, objName, false, uploadID, num, srcObj, start, end)
} }
@ -267,13 +301,14 @@ func listMultipartUploadsBase(hc *handlerContext, bktName, prefix, delimiter, up
return listPartsResponse return listPartsResponse
} }
func listParts(hc *handlerContext, bktName, objName string, uploadID string) *ListPartsResponse { func listParts(hc *handlerContext, bktName, objName string, uploadID, partNumberMarker string, status int) *ListPartsResponse {
return listPartsBase(hc, bktName, objName, false, uploadID) return listPartsBase(hc, bktName, objName, false, uploadID, partNumberMarker, status)
} }
func listPartsBase(hc *handlerContext, bktName, objName string, encrypted bool, uploadID string) *ListPartsResponse { func listPartsBase(hc *handlerContext, bktName, objName string, encrypted bool, uploadID, partNumberMarker string, status int) *ListPartsResponse {
query := make(url.Values) query := make(url.Values)
query.Set(uploadIDQuery, uploadID) query.Set(uploadIDQuery, uploadID)
query.Set(partNumberMarkerQuery, partNumberMarker)
w, r := prepareTestRequestWithQuery(hc, bktName, objName, query, nil) w, r := prepareTestRequestWithQuery(hc, bktName, objName, query, nil)
if encrypted { if encrypted {
@ -282,7 +317,7 @@ func listPartsBase(hc *handlerContext, bktName, objName string, encrypted bool,
hc.Handler().ListPartsHandler(w, r) hc.Handler().ListPartsHandler(w, r)
listPartsResponse := &ListPartsResponse{} listPartsResponse := &ListPartsResponse{}
readResponse(hc.t, w, http.StatusOK, listPartsResponse) readResponse(hc.t, w, status, listPartsResponse)
return listPartsResponse return listPartsResponse
} }

View file

@ -548,6 +548,10 @@ func (n *layer) ListParts(ctx context.Context, p *ListPartsParams) (*ListPartsIn
return parts[i].PartNumber < parts[j].PartNumber return parts[i].PartNumber < parts[j].PartNumber
}) })
if p.PartNumberMarker >= parts[len(parts)-1].PartNumber {
res.Parts = make([]*Part, 0)
return &res, nil
}
if p.PartNumberMarker != 0 { if p.PartNumberMarker != 0 {
for i, part := range parts { for i, part := range parts {
if part.PartNumber > p.PartNumberMarker { if part.PartNumber > p.PartNumberMarker {