[#617] api/handler: Simplify tests

Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
Denis Kirillov 2022-10-25 13:16:08 +03:00 committed by Alex Vanin
parent cb87fc693b
commit 18a6aca4b4
6 changed files with 166 additions and 237 deletions

View file

@ -0,0 +1,44 @@
package handler
import (
"strings"
"testing"
"github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/stretchr/testify/require"
)
func TestGetObjectPartsAttributes(t *testing.T) {
hc := prepareHandlerContext(t)
bktName := "bucket-get-attributes"
objName, objMultipartName := "object", "object-multipart"
partSize := 8
createTestBucket(hc, bktName)
putObject(t, hc, bktName, objName)
result := getObjectAttributes(hc, bktName, objName, objectParts)
require.Nil(t, result.ObjectParts)
multipartUpload := createMultipartUpload(hc, bktName, objMultipartName, map[string]string{})
etag, _ := uploadPart(hc, bktName, objMultipartName, multipartUpload.UploadID, 1, partSize)
completeMultipartUpload(hc, bktName, objMultipartName, multipartUpload.UploadID, []string{etag})
result = getObjectAttributes(hc, bktName, objMultipartName, objectParts)
require.NotNil(t, result.ObjectParts)
require.Len(t, result.ObjectParts.Parts, 1)
require.Equal(t, etag, result.ObjectParts.Parts[0].ChecksumSHA256)
require.Equal(t, partSize, result.ObjectParts.Parts[0].Size)
require.Equal(t, 1, result.ObjectParts.PartsCount)
}
func getObjectAttributes(hc *handlerContext, bktName, objName string, attrs ...string) *GetObjectAttributesResponse {
w, r := prepareTestRequest(hc, bktName, objName, nil)
r.Header.Set(api.AmzObjectAttributes, strings.Join(attrs, ","))
hc.Handler().GetObjectAttributesHandler(w, r)
result := &GetObjectAttributesResponse{}
parseTestResponse(hc.t, w, result)
return result
}

View file

@ -1,72 +0,0 @@
package handler
import (
"bytes"
"net/http"
"net/url"
"testing"
"github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/nspcc-dev/neofs-s3-gw/api/layer"
"github.com/stretchr/testify/require"
)
func TestGetObjectPartsAttributes(t *testing.T) {
hc := prepareHandlerContext(t)
bktName := "bucket-get-attributes"
objName, objMultipartName := "object", "object-multipart"
createTestBucket(hc, bktName)
body := bytes.NewReader([]byte("content"))
w, r := prepareTestPayloadRequest(hc, bktName, objName, body)
hc.Handler().PutObjectHandler(w, r)
assertStatus(t, w, http.StatusOK)
w, r = prepareTestRequest(hc, bktName, objName, nil)
r.Header.Set(api.AmzObjectAttributes, objectParts)
hc.Handler().GetObjectAttributesHandler(w, r)
result := &GetObjectAttributesResponse{}
parseTestResponse(t, w, result)
require.Nil(t, result.ObjectParts)
w, r = prepareTestRequest(hc, bktName, objMultipartName, nil)
hc.Handler().CreateMultipartUploadHandler(w, r)
multipartUpload := &InitiateMultipartUploadResponse{}
parseTestResponse(t, w, multipartUpload)
body2 := bytes.NewReader([]byte("content2"))
w, r = prepareTestPayloadRequest(hc, bktName, objMultipartName, body2)
query := make(url.Values)
query.Add(uploadIDHeaderName, multipartUpload.UploadID)
query.Add(partNumberHeaderName, "1")
r.URL.RawQuery = query.Encode()
hc.Handler().UploadPartHandler(w, r)
assertStatus(t, w, http.StatusOK)
etag := w.Result().Header.Get(api.ETag)
completeUpload := &CompleteMultipartUpload{
Parts: []*layer.CompletedPart{{
ETag: etag,
PartNumber: 1,
}},
}
w, r = prepareTestRequest(hc, bktName, objMultipartName, completeUpload)
query = make(url.Values)
query.Add(uploadIDHeaderName, multipartUpload.UploadID)
r.URL.RawQuery = query.Encode()
hc.Handler().CompleteMultipartUploadHandler(w, r)
assertStatus(t, w, http.StatusOK)
w, r = prepareTestRequest(hc, bktName, objMultipartName, nil)
r.Header.Set(api.AmzObjectAttributes, objectParts)
hc.Handler().GetObjectAttributesHandler(w, r)
result = &GetObjectAttributesResponse{}
parseTestResponse(t, w, result)
require.NotNil(t, result.ObjectParts)
require.Len(t, result.ObjectParts.Parts, 1)
require.Equal(t, etag, result.ObjectParts.Parts[0].ChecksumSHA256)
require.Equal(t, 8, result.ObjectParts.Parts[0].Size)
require.Equal(t, 1, result.ObjectParts.PartsCount)
}

View file

@ -99,7 +99,7 @@ func TestS3EncryptionSSECMultipartUpload(t *testing.T) {
api.ContentType: "text/plain",
}
data := multipartUploadEncrypted(t, tc, bktName, objName, headers, objLen, partSize)
data := multipartUploadEncrypted(tc, bktName, objName, headers, objLen, partSize)
require.Equal(t, objLen, len(data))
resData, resHeader := getEncryptedObject(t, tc, bktName, objName)
@ -143,8 +143,8 @@ func checkContentUsingRangeEnc(t *testing.T, tc *handlerContext, bktName, objNam
}
}
func multipartUploadEncrypted(t *testing.T, tc *handlerContext, bktName, objName string, headers map[string]string, objLen, partsSize int) (objData []byte) {
multipartInfo := createMultipartUpload(t, tc, bktName, objName, headers)
func multipartUploadEncrypted(hc *handlerContext, bktName, objName string, headers map[string]string, objLen, partsSize int) (objData []byte) {
multipartInfo := createMultipartUploadEncrypted(hc, bktName, objName, headers)
var sum, currentPart int
var etags []string
@ -158,26 +158,37 @@ func multipartUploadEncrypted(t *testing.T, tc *handlerContext, bktName, objName
adjustedSize = objLen - sum
}
etag, data := uploadPart(t, tc, bktName, objName, multipartInfo.UploadID, currentPart, adjustedSize)
etag, data := uploadPartEncrypted(hc, bktName, objName, multipartInfo.UploadID, currentPart, adjustedSize)
etags = append(etags, etag)
objData = append(objData, data...)
}
completeMultipartUpload(t, tc, bktName, objName, multipartInfo.UploadID, etags)
completeMultipartUpload(hc, bktName, objName, multipartInfo.UploadID, etags)
return
}
func createMultipartUpload(t *testing.T, tc *handlerContext, bktName, objName string, headers map[string]string) *InitiateMultipartUploadResponse {
w, r := prepareTestRequest(tc, bktName, objName, nil)
func createMultipartUploadEncrypted(hc *handlerContext, bktName, objName string, headers map[string]string) *InitiateMultipartUploadResponse {
return createMultipartUploadBase(hc, bktName, objName, true, headers)
}
func createMultipartUpload(hc *handlerContext, bktName, objName string, headers map[string]string) *InitiateMultipartUploadResponse {
return createMultipartUploadBase(hc, bktName, objName, false, headers)
}
func createMultipartUploadBase(hc *handlerContext, bktName, objName string, encrypted bool, headers map[string]string) *InitiateMultipartUploadResponse {
w, r := prepareTestRequest(hc, bktName, objName, nil)
if encrypted {
setEncryptHeaders(r)
}
setHeaders(r, headers)
tc.Handler().CreateMultipartUploadHandler(w, r)
hc.Handler().CreateMultipartUploadHandler(w, r)
multipartInitInfo := &InitiateMultipartUploadResponse{}
readResponse(t, w, http.StatusOK, multipartInitInfo)
readResponse(hc.t, w, http.StatusOK, multipartInitInfo)
return multipartInitInfo
}
func completeMultipartUpload(t *testing.T, tc *handlerContext, bktName, objName, uploadID string, partsETags []string) {
func completeMultipartUpload(hc *handlerContext, bktName, objName, uploadID string, partsETags []string) {
query := make(url.Values)
query.Set(uploadIDQuery, uploadID)
complete := &CompleteMultipartUpload{
@ -190,24 +201,34 @@ func completeMultipartUpload(t *testing.T, tc *handlerContext, bktName, objName,
})
}
w, r := prepareTestFullRequest(tc, bktName, objName, query, complete)
tc.Handler().CompleteMultipartUploadHandler(w, r)
assertStatus(t, w, http.StatusOK)
w, r := prepareTestFullRequest(hc, bktName, objName, query, complete)
hc.Handler().CompleteMultipartUploadHandler(w, r)
assertStatus(hc.t, w, http.StatusOK)
}
func uploadPart(t *testing.T, tc *handlerContext, bktName, objName, uploadID string, num, size int) (string, []byte) {
func uploadPartEncrypted(hc *handlerContext, bktName, objName, uploadID string, num, size int) (string, []byte) {
return uploadPartBase(hc, bktName, objName, true, uploadID, num, size)
}
func uploadPart(hc *handlerContext, bktName, objName, uploadID string, num, size int) (string, []byte) {
return uploadPartBase(hc, bktName, objName, false, uploadID, num, size)
}
func uploadPartBase(hc *handlerContext, bktName, objName string, encrypted bool, uploadID string, num, size int) (string, []byte) {
partBody := make([]byte, size)
_, err := rand.Read(partBody)
require.NoError(t, err)
require.NoError(hc.t, err)
query := make(url.Values)
query.Set(uploadIDQuery, uploadID)
query.Set(partNumberQuery, strconv.Itoa(num))
w, r := prepareTestRequestWithQuery(tc, bktName, objName, query, partBody)
w, r := prepareTestRequestWithQuery(hc, bktName, objName, query, partBody)
if encrypted {
setEncryptHeaders(r)
tc.Handler().UploadPartHandler(w, r)
assertStatus(t, w, http.StatusOK)
}
hc.Handler().UploadPartHandler(w, r)
assertStatus(hc.t, w, http.StatusOK)
return w.Header().Get(api.ETag), partBody
}
@ -215,57 +236,21 @@ func uploadPart(t *testing.T, tc *handlerContext, bktName, objName, uploadID str
func TestMultipartEncrypted(t *testing.T) {
partSize := 5*1048576 + 1<<16 - 5 // 5MB (min part size) + 64kb (cipher block size) - 5 (to check corner range)
tc := prepareHandlerContext(t)
hc := prepareHandlerContext(t)
bktName, objName := "bucket-for-sse-c-multipart", "object-to-encrypt-multipart"
createTestBucket(tc, bktName)
createTestBucket(hc, bktName)
w, r := prepareTestRequest(tc, bktName, objName, nil)
setEncryptHeaders(r)
tc.Handler().CreateMultipartUploadHandler(w, r)
multipartInitInfo := &InitiateMultipartUploadResponse{}
readResponse(t, w, http.StatusOK, multipartInitInfo)
multipartInitInfo := createMultipartUploadEncrypted(hc, bktName, objName, map[string]string{})
part1ETag, part1 := uploadPartEncrypted(hc, bktName, objName, multipartInitInfo.UploadID, 1, partSize)
part2ETag, part2 := uploadPartEncrypted(hc, bktName, objName, multipartInitInfo.UploadID, 2, 5)
completeMultipartUpload(hc, bktName, objName, multipartInitInfo.UploadID, []string{part1ETag, part2ETag})
part1 := make([]byte, partSize)
for i := range part1 {
part1[i] = 'a'
}
query := make(url.Values)
query.Set(uploadIDQuery, multipartInitInfo.UploadID)
query.Set(partNumberQuery, "1")
w, r = prepareTestRequestWithQuery(tc, bktName, objName, query, part1)
setEncryptHeaders(r)
tc.Handler().UploadPartHandler(w, r)
assertStatus(t, w, http.StatusOK)
part1ETag := w.Header().Get(api.ETag)
part2 := []byte("part2")
query = make(url.Values)
query.Set(uploadIDQuery, multipartInitInfo.UploadID)
query.Set(partNumberQuery, "2")
w, r = prepareTestRequestWithQuery(tc, bktName, objName, query, part2)
setEncryptHeaders(r)
tc.Handler().UploadPartHandler(w, r)
assertStatus(t, w, http.StatusOK)
part2ETag := w.Header().Get(api.ETag)
query = make(url.Values)
query.Set(uploadIDQuery, multipartInitInfo.UploadID)
complete := &CompleteMultipartUpload{
Parts: []*layer.CompletedPart{
{ETag: part1ETag, PartNumber: 1},
{ETag: part2ETag, PartNumber: 2},
},
}
w, r = prepareTestFullRequest(tc, bktName, objName, query, complete)
tc.Handler().CompleteMultipartUploadHandler(w, r)
assertStatus(t, w, http.StatusOK)
res, _ := getEncryptedObject(t, tc, bktName, objName)
res, _ := getEncryptedObject(t, hc, bktName, objName)
require.Equal(t, len(part1)+len(part2), len(res))
require.Equal(t, append(part1, part2...), res)
part2Range := getEncryptedObjectRange(t, tc, bktName, objName, len(part1), len(part1)+len(part2)-1)
part2Range := getEncryptedObjectRange(t, hc, bktName, objName, len(part1), len(part1)+len(part2)-1)
require.Equal(t, part2[0:], part2Range)
}

View file

@ -155,7 +155,7 @@ func TestGetRange(t *testing.T) {
createTestBucket(tc, bktName)
content := "123456789abcdef"
putObjectContent(t, tc, bktName, objName, content)
putObjectContent(tc, bktName, objName, content)
full := getObjectRange(t, tc, bktName, objName, 0, len(content)-1)
require.Equal(t, content, string(full))
@ -170,11 +170,11 @@ func TestGetRange(t *testing.T) {
require.Equal(t, "bcdef", string(end))
}
func putObjectContent(t *testing.T, tc *handlerContext, bktName, objName, content string) {
func putObjectContent(hc *handlerContext, bktName, objName, content string) {
body := bytes.NewReader([]byte(content))
w, r := prepareTestPayloadRequest(tc, bktName, objName, body)
tc.Handler().PutObjectHandler(w, r)
assertStatus(t, w, http.StatusOK)
w, r := prepareTestPayloadRequest(hc, bktName, objName, body)
hc.Handler().PutObjectHandler(w, r)
assertStatus(hc.t, w, http.StatusOK)
}
func getObjectRange(t *testing.T, tc *handlerContext, bktName, objName string, start, end int) []byte {

View file

@ -423,35 +423,31 @@ func TestObjectLegalHold(t *testing.T) {
objName := "obj-for-legal-hold"
createTestObject(hc, bktInfo, objName)
getObjectLegalHold(hc, bktName, objName, legalHoldOff)
putObjectLegalHold(hc, bktName, objName, legalHoldOn)
getObjectLegalHold(hc, bktName, objName, legalHoldOn)
// to make sure put hold is an idempotent operation
putObjectLegalHold(hc, bktName, objName, legalHoldOn)
putObjectLegalHold(hc, bktName, objName, legalHoldOff)
getObjectLegalHold(hc, bktName, objName, legalHoldOff)
// to make sure put hold is an idempotent operation
putObjectLegalHold(hc, bktName, objName, legalHoldOff)
}
func getObjectLegalHold(hc *handlerContext, bktName, objName, status string) {
w, r := prepareTestRequest(hc, bktName, objName, nil)
hc.Handler().GetObjectLegalHoldHandler(w, r)
assertLegalHold(t, w, legalHoldOff)
assertLegalHold(hc.t, w, status)
}
w, r = prepareTestRequest(hc, bktName, objName, &data.LegalHold{Status: legalHoldOn})
func putObjectLegalHold(hc *handlerContext, bktName, objName, status string) {
w, r := prepareTestRequest(hc, bktName, objName, &data.LegalHold{Status: status})
hc.Handler().PutObjectLegalHoldHandler(w, r)
assertStatus(t, w, http.StatusOK)
w, r = prepareTestRequest(hc, bktName, objName, nil)
hc.Handler().GetObjectLegalHoldHandler(w, r)
assertLegalHold(t, w, legalHoldOn)
// to make sure put hold is an idempotent operation
w, r = prepareTestRequest(hc, bktName, objName, &data.LegalHold{Status: legalHoldOn})
hc.Handler().PutObjectLegalHoldHandler(w, r)
assertStatus(t, w, http.StatusOK)
w, r = prepareTestRequest(hc, bktName, objName, &data.LegalHold{Status: legalHoldOff})
hc.Handler().PutObjectLegalHoldHandler(w, r)
assertStatus(t, w, http.StatusOK)
w, r = prepareTestRequest(hc, bktName, objName, nil)
hc.Handler().GetObjectLegalHoldHandler(w, r)
assertLegalHold(t, w, legalHoldOff)
// to make sure put hold is an idempotent operation
w, r = prepareTestRequest(hc, bktName, objName, &data.LegalHold{Status: legalHoldOff})
hc.Handler().PutObjectLegalHoldHandler(w, r)
assertStatus(t, w, http.StatusOK)
assertStatus(hc.t, w, http.StatusOK)
}
func assertLegalHold(t *testing.T, w *httptest.ResponseRecorder, status string) {
@ -471,38 +467,43 @@ func TestObjectRetention(t *testing.T) {
objName := "obj-for-retention"
createTestObject(hc, bktInfo, objName)
w, r := prepareTestRequest(hc, bktName, objName, nil)
hc.Handler().GetObjectRetentionHandler(w, r)
assertS3Error(t, w, apiErrors.GetAPIError(apiErrors.ErrNoSuchKey))
getObjectRetention(hc, bktName, objName, nil, apiErrors.ErrNoSuchKey)
retention := &data.Retention{Mode: governanceMode, RetainUntilDate: time.Now().Add(time.Minute).UTC().Format(time.RFC3339)}
w, r = prepareTestRequest(hc, bktName, objName, retention)
hc.Handler().PutObjectRetentionHandler(w, r)
assertStatus(t, w, http.StatusOK)
w, r = prepareTestRequest(hc, bktName, objName, nil)
hc.Handler().GetObjectRetentionHandler(w, r)
assertRetention(t, w, retention)
putObjectRetention(hc, bktName, objName, retention, false, 0)
getObjectRetention(hc, bktName, objName, retention, 0)
retention = &data.Retention{Mode: governanceMode, RetainUntilDate: time.Now().UTC().Add(time.Minute).Format(time.RFC3339)}
w, r = prepareTestRequest(hc, bktName, objName, retention)
hc.Handler().PutObjectRetentionHandler(w, r)
assertS3Error(t, w, apiErrors.GetAPIError(apiErrors.ErrInternalError))
putObjectRetention(hc, bktName, objName, retention, false, apiErrors.ErrInternalError)
retention = &data.Retention{Mode: complianceMode, RetainUntilDate: time.Now().Add(time.Minute).UTC().Format(time.RFC3339)}
w, r = prepareTestRequest(hc, bktName, objName, retention)
r.Header.Set(api.AmzBypassGovernanceRetention, strconv.FormatBool(true))
hc.Handler().PutObjectRetentionHandler(w, r)
assertStatus(t, w, http.StatusOK)
putObjectRetention(hc, bktName, objName, retention, true, 0)
getObjectRetention(hc, bktName, objName, retention, 0)
w, r = prepareTestRequest(hc, bktName, objName, nil)
putObjectRetention(hc, bktName, objName, retention, true, apiErrors.ErrInternalError)
}
func getObjectRetention(hc *handlerContext, bktName, objName string, retention *data.Retention, errCode apiErrors.ErrorCode) {
w, r := prepareTestRequest(hc, bktName, objName, nil)
hc.Handler().GetObjectRetentionHandler(w, r)
assertRetention(t, w, retention)
if errCode == 0 {
assertRetention(hc.t, w, retention)
} else {
assertS3Error(hc.t, w, apiErrors.GetAPIError(errCode))
}
}
w, r = prepareTestRequest(hc, bktName, objName, retention)
func putObjectRetention(hc *handlerContext, bktName, objName string, retention *data.Retention, byPass bool, errCode apiErrors.ErrorCode) {
w, r := prepareTestRequest(hc, bktName, objName, retention)
if byPass {
r.Header.Set(api.AmzBypassGovernanceRetention, strconv.FormatBool(true))
}
hc.Handler().PutObjectRetentionHandler(w, r)
assertS3Error(t, w, apiErrors.GetAPIError(apiErrors.ErrInternalError))
if errCode == 0 {
assertStatus(hc.t, w, http.StatusOK)
} else {
assertS3Error(hc.t, w, apiErrors.GetAPIError(errCode))
}
}
func assertRetention(t *testing.T, w *httptest.ResponseRecorder, retention *data.Retention) {
@ -530,25 +531,13 @@ func TestPutObjectWithLock(t *testing.T) {
createTestBucketWithLock(hc, bktName, lockConfig)
objDefault := "obj-default-retention"
putObject(t, hc, bktName, objDefault)
w, r := prepareTestRequest(hc, bktName, objDefault, nil)
hc.Handler().PutObjectHandler(w, r)
assertStatus(t, w, http.StatusOK)
w, r = prepareTestRequest(hc, bktName, objDefault, nil)
hc.Handler().GetObjectRetentionHandler(w, r)
expectedRetention := &data.Retention{
Mode: governanceMode,
RetainUntilDate: time.Now().Add(24 * time.Hour).Format(time.RFC3339),
}
assertRetentionApproximate(t, w, expectedRetention, 1)
w, r = prepareTestRequest(hc, bktName, objDefault, nil)
hc.Handler().GetObjectLegalHoldHandler(w, r)
assertLegalHold(t, w, legalHoldOff)
getObjectRetentionApproximate(hc, bktName, objDefault, governanceMode, time.Now().Add(24*time.Hour))
getObjectLegalHold(hc, bktName, objDefault, legalHoldOff)
objOverride := "obj-override-retention"
w, r = prepareTestRequest(hc, bktName, objOverride, nil)
w, r := prepareTestRequest(hc, bktName, objOverride, nil)
r.Header.Set(api.AmzObjectLockMode, complianceMode)
r.Header.Set(api.AmzObjectLockLegalHold, legalHoldOn)
r.Header.Set(api.AmzBypassGovernanceRetention, "true")
@ -556,17 +545,18 @@ func TestPutObjectWithLock(t *testing.T) {
hc.Handler().PutObjectHandler(w, r)
assertStatus(t, w, http.StatusOK)
w, r = prepareTestRequest(hc, bktName, objOverride, nil)
hc.Handler().GetObjectRetentionHandler(w, r)
expectedRetention = &data.Retention{
Mode: complianceMode,
RetainUntilDate: time.Now().Add(2 * 24 * time.Hour).Format(time.RFC3339),
getObjectRetentionApproximate(hc, bktName, objOverride, complianceMode, time.Now().Add(2*24*time.Hour))
getObjectLegalHold(hc, bktName, objOverride, legalHoldOn)
}
assertRetentionApproximate(t, w, expectedRetention, 1)
w, r = prepareTestRequest(hc, bktName, objOverride, nil)
hc.Handler().GetObjectLegalHoldHandler(w, r)
assertLegalHold(t, w, legalHoldOn)
func getObjectRetentionApproximate(hc *handlerContext, bktName, objName, mode string, untilDate time.Time) {
w, r := prepareTestRequest(hc, bktName, objName, nil)
hc.Handler().GetObjectRetentionHandler(w, r)
expectedRetention := &data.Retention{
Mode: mode,
RetainUntilDate: untilDate.Format(time.RFC3339),
}
assertRetentionApproximate(hc.t, w, expectedRetention, 1)
}
func TestPutLockErrors(t *testing.T) {

View file

@ -1,7 +1,6 @@
package handler
import (
"bytes"
"net/http"
"net/url"
"strconv"
@ -44,31 +43,14 @@ func TestParseContinuationToken(t *testing.T) {
func TestListObjectNullVersions(t *testing.T) {
hc := prepareHandlerContext(t)
bktName := "bucket-versioning-enabled"
bktName, objName := "bucket-versioning-enabled", "object"
createTestBucket(hc, bktName)
objName := "object"
putObjectContent(hc, bktName, objName, "content")
putBucketVersioning(t, hc, bktName, true)
putObjectContent(hc, bktName, objName, "content2")
body := bytes.NewReader([]byte("content"))
w, r := prepareTestPayloadRequest(hc, bktName, objName, body)
hc.Handler().PutObjectHandler(w, r)
assertStatus(t, w, http.StatusOK)
versioning := &VersioningConfiguration{Status: "Enabled"}
w, r = prepareTestRequest(hc, bktName, objName, versioning)
hc.Handler().PutBucketVersioningHandler(w, r)
assertStatus(t, w, http.StatusOK)
body2 := bytes.NewReader([]byte("content2"))
w, r = prepareTestPayloadRequest(hc, bktName, objName, body2)
hc.Handler().PutObjectHandler(w, r)
assertStatus(t, w, http.StatusOK)
w, r = prepareTestRequest(hc, bktName, objName, nil)
hc.Handler().ListBucketObjectVersionsHandler(w, r)
result := &ListObjectsVersionsResponse{}
parseTestResponse(t, w, result)
result := listVersions(t, hc, bktName)
require.Len(t, result.Version, 2)
require.Equal(t, data.UnversionedObjectVersionID, result.Version[1].VersionID)