2022-06-15 12:17:29 +00:00
|
|
|
package handler
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/nspcc-dev/neofs-s3-gw/api"
|
2022-06-24 12:39:30 +00:00
|
|
|
"github.com/nspcc-dev/neofs-s3-gw/api/data"
|
2022-06-15 12:17:29 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
const (
|
|
|
|
emptyVersion = ""
|
|
|
|
)
|
|
|
|
|
2022-06-15 12:17:29 +00:00
|
|
|
func TestDeleteObject(t *testing.T) {
|
|
|
|
tc := prepareHandlerContext(t)
|
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
bktName, objName := "bucket-for-removal", "object-to-delete"
|
|
|
|
bktInfo, objInfo := createBucketAndObject(t, tc, bktName, objName)
|
2022-06-15 12:17:29 +00:00
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
checkFound(t, tc, bktName, objName, emptyVersion)
|
|
|
|
deleteObject(t, tc, bktName, objName, emptyVersion)
|
|
|
|
checkNotFound(t, tc, bktName, objName, emptyVersion)
|
2022-06-15 12:17:29 +00:00
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
require.False(t, existInMockedNeoFS(tc, bktInfo, objInfo))
|
|
|
|
}
|
2022-06-15 12:17:29 +00:00
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
func TestDeleteObjectVersioned(t *testing.T) {
|
|
|
|
tc := prepareHandlerContext(t)
|
2022-06-15 12:17:29 +00:00
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
bktName, objName := "bucket-for-removal", "object-to-delete"
|
|
|
|
bktInfo, objInfo := createVersionedBucketAndObject(t, tc, bktName, objName)
|
2022-06-15 12:17:29 +00:00
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
checkFound(t, tc, bktName, objName, emptyVersion)
|
|
|
|
deleteObject(t, tc, bktName, objName, emptyVersion)
|
|
|
|
checkNotFound(t, tc, bktName, objName, emptyVersion)
|
|
|
|
|
|
|
|
checkFound(t, tc, bktName, objName, objInfo.Version())
|
|
|
|
deleteObject(t, tc, bktName, objName, objInfo.Version())
|
|
|
|
checkNotFound(t, tc, bktName, objName, objInfo.Version())
|
2022-06-15 12:17:29 +00:00
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
require.False(t, existInMockedNeoFS(tc, bktInfo, objInfo), "object exists but shouldn't")
|
2022-06-15 12:17:29 +00:00
|
|
|
}
|
|
|
|
|
2022-07-01 09:32:31 +00:00
|
|
|
func TestDeleteObjectUnversioned(t *testing.T) {
|
|
|
|
tc := prepareHandlerContext(t)
|
|
|
|
|
|
|
|
bktName, objName := "bucket-for-removal-unversioned", "object-to-delete-unversioned"
|
|
|
|
bktInfo, objInfo := createBucketAndObject(t, tc, bktName, objName)
|
|
|
|
|
|
|
|
checkFound(t, tc, bktName, objName, emptyVersion)
|
|
|
|
deleteObject(t, tc, bktName, objName, emptyVersion)
|
|
|
|
checkNotFound(t, tc, bktName, objName, emptyVersion)
|
|
|
|
|
|
|
|
versions := listVersions(t, tc, bktName)
|
|
|
|
require.Len(t, versions.DeleteMarker, 0, "delete markers must be empty")
|
|
|
|
require.Len(t, versions.Version, 0, "versions must be empty")
|
|
|
|
|
|
|
|
require.False(t, existInMockedNeoFS(tc, bktInfo, objInfo), "object exists but shouldn't")
|
|
|
|
}
|
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
func TestRemoveDeleteMarker(t *testing.T) {
|
2022-06-15 12:17:29 +00:00
|
|
|
tc := prepareHandlerContext(t)
|
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
bktName, objName := "bucket-for-removal", "object-to-delete"
|
|
|
|
bktInfo, objInfo := createVersionedBucketAndObject(t, tc, bktName, objName)
|
2022-06-15 12:17:29 +00:00
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
checkFound(t, tc, bktName, objName, emptyVersion)
|
|
|
|
deleteMarkerVersion := deleteObject(t, tc, bktName, objName, emptyVersion)
|
|
|
|
checkNotFound(t, tc, bktName, objName, emptyVersion)
|
2022-06-15 12:17:29 +00:00
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
checkFound(t, tc, bktName, objName, objInfo.Version())
|
|
|
|
deleteObject(t, tc, bktName, objName, deleteMarkerVersion)
|
|
|
|
checkNotFound(t, tc, bktName, objName, emptyVersion)
|
2022-06-15 12:17:29 +00:00
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
require.True(t, existInMockedNeoFS(tc, bktInfo, objInfo), "object doesn't exist but should")
|
|
|
|
}
|
2022-06-15 12:17:29 +00:00
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
func TestDeleteObjectCombined(t *testing.T) {
|
|
|
|
tc := prepareHandlerContext(t)
|
2022-06-15 12:17:29 +00:00
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
bktName, objName := "bucket-for-removal", "object-to-delete"
|
|
|
|
bktInfo, objInfo := createBucketAndObject(t, tc, bktName, objName)
|
2022-06-15 12:17:29 +00:00
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
putBucketVersioning(t, tc, bktName, true)
|
2022-06-15 12:17:29 +00:00
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
checkFound(t, tc, bktName, objName, emptyVersion)
|
|
|
|
deleteObject(t, tc, bktName, objName, emptyVersion)
|
|
|
|
checkNotFound(t, tc, bktName, objName, emptyVersion)
|
2022-06-15 12:17:29 +00:00
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
checkFound(t, tc, bktName, objName, objInfo.Version())
|
2022-06-15 12:17:29 +00:00
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
require.True(t, existInMockedNeoFS(tc, bktInfo, objInfo), "object doesn't exist but should")
|
2022-06-15 12:17:29 +00:00
|
|
|
}
|
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
func TestDeleteObjectSuspended(t *testing.T) {
|
2022-06-15 12:17:29 +00:00
|
|
|
tc := prepareHandlerContext(t)
|
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
bktName, objName := "bucket-for-removal", "object-to-delete"
|
|
|
|
bktInfo, objInfo := createBucketAndObject(t, tc, bktName, objName)
|
|
|
|
|
|
|
|
putBucketVersioning(t, tc, bktName, true)
|
|
|
|
|
|
|
|
checkFound(t, tc, bktName, objName, emptyVersion)
|
|
|
|
deleteObject(t, tc, bktName, objName, emptyVersion)
|
|
|
|
checkNotFound(t, tc, bktName, objName, emptyVersion)
|
|
|
|
|
|
|
|
putBucketVersioning(t, tc, bktName, false)
|
|
|
|
|
|
|
|
deleteObject(t, tc, bktName, objName, emptyVersion)
|
|
|
|
checkNotFound(t, tc, bktName, objName, objInfo.Version())
|
|
|
|
|
|
|
|
require.False(t, existInMockedNeoFS(tc, bktInfo, objInfo), "object exists but shouldn't")
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDeleteMarkers(t *testing.T) {
|
|
|
|
tc := prepareHandlerContext(t)
|
|
|
|
|
|
|
|
bktName, objName := "bucket-for-removal", "object-to-delete"
|
|
|
|
createTestBucket(tc.Context(), t, tc, bktName)
|
|
|
|
putBucketVersioning(t, tc, bktName, true)
|
|
|
|
|
|
|
|
checkNotFound(t, tc, bktName, objName, emptyVersion)
|
|
|
|
deleteObject(t, tc, bktName, objName, emptyVersion)
|
|
|
|
deleteObject(t, tc, bktName, objName, emptyVersion)
|
|
|
|
deleteObject(t, tc, bktName, objName, emptyVersion)
|
|
|
|
|
|
|
|
versions := listVersions(t, tc, bktName)
|
|
|
|
require.Len(t, versions.DeleteMarker, 3, "invalid delete markers length")
|
|
|
|
require.Len(t, versions.Version, 0, "versions must be empty")
|
|
|
|
|
|
|
|
require.Len(t, listOIDsFromMockedNeoFS(t, tc, bktName, objName), 0, "shouldn't be any object in neofs")
|
|
|
|
}
|
|
|
|
|
2022-07-05 06:25:23 +00:00
|
|
|
func TestDeleteObjectFromListCache(t *testing.T) {
|
|
|
|
tc := prepareHandlerContext(t)
|
|
|
|
|
|
|
|
bktName, objName := "bucket-for-removal", "object-to-delete"
|
|
|
|
bktInfo, objInfo := createVersionedBucketAndObject(t, tc, bktName, objName)
|
|
|
|
|
|
|
|
versions := listObjectsV1(t, tc, bktName)
|
|
|
|
require.Len(t, versions.Contents, 1)
|
|
|
|
|
|
|
|
checkFound(t, tc, bktName, objName, objInfo.Version())
|
|
|
|
deleteObject(t, tc, bktName, objName, objInfo.Version())
|
|
|
|
checkNotFound(t, tc, bktName, objName, objInfo.Version())
|
|
|
|
|
|
|
|
// check cache is clean after object removal
|
|
|
|
versions = listObjectsV1(t, tc, bktName)
|
|
|
|
require.Len(t, versions.Contents, 0)
|
|
|
|
|
|
|
|
require.False(t, existInMockedNeoFS(tc, bktInfo, objInfo))
|
|
|
|
}
|
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
func createBucketAndObject(t *testing.T, tc *handlerContext, bktName, objName string) (*data.BucketInfo, *data.ObjectInfo) {
|
|
|
|
createTestBucket(tc.Context(), t, tc, bktName)
|
|
|
|
bktInfo, err := tc.Layer().GetBucketInfo(tc.Context(), bktName)
|
2022-06-15 12:17:29 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
objInfo := createTestObject(tc.Context(), t, tc, bktInfo, objName)
|
2022-06-15 12:17:29 +00:00
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
return bktInfo, objInfo
|
|
|
|
}
|
|
|
|
|
|
|
|
func createVersionedBucketAndObject(t *testing.T, tc *handlerContext, bktName, objName string) (*data.BucketInfo, *data.ObjectInfo) {
|
|
|
|
createTestBucket(tc.Context(), t, tc, bktName)
|
|
|
|
bktInfo, err := tc.Layer().GetBucketInfo(tc.Context(), bktName)
|
|
|
|
require.NoError(t, err)
|
|
|
|
putBucketVersioning(t, tc, bktName, true)
|
2022-06-15 12:17:29 +00:00
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
objInfo := createTestObject(tc.Context(), t, tc, bktInfo, objName)
|
|
|
|
|
|
|
|
return bktInfo, objInfo
|
|
|
|
}
|
|
|
|
|
|
|
|
func putBucketVersioning(t *testing.T, tc *handlerContext, bktName string, enabled bool) {
|
|
|
|
cfg := &VersioningConfiguration{Status: "Suspended"}
|
|
|
|
if enabled {
|
|
|
|
cfg.Status = "Enabled"
|
|
|
|
}
|
|
|
|
w, r := prepareTestRequest(t, bktName, "", cfg)
|
2022-06-15 12:17:29 +00:00
|
|
|
tc.Handler().PutBucketVersioningHandler(w, r)
|
|
|
|
assertStatus(t, w, http.StatusOK)
|
2022-06-24 12:39:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func deleteObject(t *testing.T, tc *handlerContext, bktName, objName, version string) string {
|
|
|
|
query := make(url.Values)
|
|
|
|
query.Add(api.QueryVersionID, version)
|
2022-06-15 12:17:29 +00:00
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
w, r := prepareTestFullRequest(t, bktName, objName, query, nil)
|
2022-06-15 12:17:29 +00:00
|
|
|
tc.Handler().DeleteObjectHandler(w, r)
|
|
|
|
assertStatus(t, w, http.StatusNoContent)
|
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
return w.Header().Get(api.AmzVersionID)
|
|
|
|
}
|
|
|
|
|
|
|
|
func checkNotFound(t *testing.T, tc *handlerContext, bktName, objName, version string) {
|
|
|
|
query := make(url.Values)
|
|
|
|
query.Add(api.QueryVersionID, version)
|
|
|
|
|
|
|
|
w, r := prepareTestFullRequest(t, bktName, objName, query, nil)
|
2022-06-15 12:17:29 +00:00
|
|
|
tc.Handler().HeadObjectHandler(w, r)
|
|
|
|
assertStatus(t, w, http.StatusNotFound)
|
2022-06-24 12:39:30 +00:00
|
|
|
}
|
2022-06-15 12:17:29 +00:00
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
func checkFound(t *testing.T, tc *handlerContext, bktName, objName, version string) {
|
2022-06-15 12:17:29 +00:00
|
|
|
query := make(url.Values)
|
2022-06-24 12:39:30 +00:00
|
|
|
query.Add(api.QueryVersionID, version)
|
2022-06-15 12:17:29 +00:00
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
w, r := prepareTestFullRequest(t, bktName, objName, query, nil)
|
2022-06-15 12:17:29 +00:00
|
|
|
tc.Handler().HeadObjectHandler(w, r)
|
2022-06-24 12:39:30 +00:00
|
|
|
assertStatus(t, w, http.StatusOK)
|
|
|
|
}
|
2022-06-15 12:17:29 +00:00
|
|
|
|
2022-06-24 12:39:30 +00:00
|
|
|
func listVersions(t *testing.T, tc *handlerContext, bktName string) *ListObjectsVersionsResponse {
|
|
|
|
w, r := prepareTestRequest(t, bktName, "", nil)
|
|
|
|
tc.Handler().ListBucketObjectVersionsHandler(w, r)
|
|
|
|
assertStatus(t, w, http.StatusOK)
|
|
|
|
res := &ListObjectsVersionsResponse{}
|
|
|
|
parseTestResponse(t, w, res)
|
|
|
|
return res
|
2022-06-15 12:17:29 +00:00
|
|
|
}
|
2022-07-05 06:25:23 +00:00
|
|
|
|
|
|
|
func listObjectsV1(t *testing.T, tc *handlerContext, bktName string) *ListObjectsV1Response {
|
|
|
|
w, r := prepareTestRequest(t, bktName, "", nil)
|
|
|
|
tc.Handler().ListObjectsV1Handler(w, r)
|
|
|
|
assertStatus(t, w, http.StatusOK)
|
|
|
|
res := &ListObjectsV1Response{}
|
|
|
|
parseTestResponse(t, w, res)
|
|
|
|
return res
|
|
|
|
}
|