diff --git a/api/handler/attributes_test.go b/api/handler/attributes_test.go index 23ca8ac7..2889d73e 100644 --- a/api/handler/attributes_test.go +++ b/api/handler/attributes_test.go @@ -17,7 +17,7 @@ func TestGetObjectPartsAttributes(t *testing.T) { createTestBucket(hc, bktName) - putObject(t, hc, bktName, objName) + putObject(hc, bktName, objName) result := getObjectAttributes(hc, bktName, objName, objectParts) require.Nil(t, result.ObjectParts) diff --git a/api/handler/delete_test.go b/api/handler/delete_test.go index f084e463..6c44ec3e 100644 --- a/api/handler/delete_test.go +++ b/api/handler/delete_test.go @@ -25,7 +25,7 @@ func TestDeleteBucketOnAlreadyRemovedError(t *testing.T) { bktName, objName := "bucket-for-removal", "object-to-delete" bktInfo := createTestBucket(hc, bktName) - putObject(t, hc, bktName, objName) + putObject(hc, bktName, objName) addr := getAddressOfLastVersion(hc, bktInfo, objName) hc.tp.SetObjectError(addr, &apistatus.ObjectAlreadyRemoved{}) @@ -66,7 +66,7 @@ func TestDeleteBucketOnNotFoundError(t *testing.T) { bktName, objName := "bucket-for-removal", "object-to-delete" bktInfo := createTestBucket(hc, bktName) - putObject(t, hc, bktName, objName) + putObject(hc, bktName, objName) nodeVersion, err := hc.tree.GetUnversioned(hc.context, bktInfo, objName) require.NoError(t, err) @@ -98,7 +98,7 @@ func TestDeleteObjectFromSuspended(t *testing.T) { bktName, objName := "bucket-versioned-for-removal", "object-to-delete" createSuspendedBucket(t, tc, bktName) - putObject(t, tc, bktName, objName) + putObject(tc, bktName, objName) versionID, isDeleteMarker := deleteObject(t, tc, bktName, objName, emptyVersion) require.True(t, isDeleteMarker) @@ -255,7 +255,7 @@ func TestDeleteMarkerSuspended(t *testing.T) { t.Run("remove last unversioned non delete marker", func(t *testing.T) { objName := "obj3" - putObject(t, tc, bktName, objName) + putObject(tc, bktName, objName) nodeVersion, err := tc.tree.GetUnversioned(tc.Context(), bktInfo, objName) require.NoError(t, err) @@ -475,11 +475,11 @@ func getVersion(resp *ListObjectsVersionsResponse, objName string) []*ObjectVers return res } -func putObject(t *testing.T, tc *handlerContext, bktName, objName string) { +func putObject(hc *handlerContext, bktName, objName 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 createSuspendedBucket(t *testing.T, tc *handlerContext, bktName string) *data.BucketInfo { diff --git a/api/handler/get_test.go b/api/handler/get_test.go index 6a480efb..78c0fbc4 100644 --- a/api/handler/get_test.go +++ b/api/handler/get_test.go @@ -186,7 +186,7 @@ func TestGetObject(t *testing.T) { bktName, objName := "bucket", "obj" bktInfo, objInfo := createVersionedBucketAndObject(hc.t, hc, bktName, objName) - putObject(hc.t, hc, bktName, objName) + putObject(hc, bktName, objName) checkFound(hc.t, hc, bktName, objName, objInfo.VersionID()) checkFound(hc.t, hc, bktName, objName, emptyVersion) diff --git a/api/handler/handlers_test.go b/api/handler/handlers_test.go index 91d96f83..a6d6b071 100644 --- a/api/handler/handlers_test.go +++ b/api/handler/handlers_test.go @@ -38,6 +38,8 @@ type handlerContext struct { tree *tree.Tree context context.Context kludge *kludgeSettingsMock + + layerFeatures *layer.FeatureSettingsMock } func (hc *handlerContext) Handler() *handler { @@ -123,11 +125,14 @@ func prepareHandlerContextBase(t *testing.T, minCache bool) *handlerContext { cacheCfg = getMinCacheConfig(l) } + features := &layer.FeatureSettingsMock{} + layerCfg := &layer.Config{ Caches: cacheCfg, AnonKey: layer.AnonymousKey{Key: key}, Resolver: testResolver, TreeService: treeMock, + Features: features, } var pp netmap.PlacementPolicy @@ -154,6 +159,8 @@ func prepareHandlerContextBase(t *testing.T, minCache bool) *handlerContext { tree: treeMock, context: middleware.SetBoxData(context.Background(), newTestAccessBox(t, key)), kludge: kludge, + + layerFeatures: features, } } diff --git a/api/handler/head_test.go b/api/handler/head_test.go index e2c943c3..821f651f 100644 --- a/api/handler/head_test.go +++ b/api/handler/head_test.go @@ -114,7 +114,7 @@ func TestHeadObject(t *testing.T) { bktName, objName := "bucket", "obj" bktInfo, objInfo := createVersionedBucketAndObject(hc.t, hc, bktName, objName) - putObject(hc.t, hc, bktName, objName) + putObject(hc, bktName, objName) checkFound(hc.t, hc, bktName, objName, objInfo.VersionID()) checkFound(hc.t, hc, bktName, objName, emptyVersion) diff --git a/api/handler/locking_test.go b/api/handler/locking_test.go index 0e1986de..7e415a4e 100644 --- a/api/handler/locking_test.go +++ b/api/handler/locking_test.go @@ -536,7 +536,7 @@ func TestPutObjectWithLock(t *testing.T) { createTestBucketWithLock(hc, bktName, lockConfig) objDefault := "obj-default-retention" - putObject(t, hc, bktName, objDefault) + putObject(hc, bktName, objDefault) getObjectRetentionApproximate(hc, bktName, objDefault, governanceMode, time.Now().Add(24*time.Hour)) getObjectLegalHold(hc, bktName, objDefault, legalHoldOff) @@ -587,7 +587,7 @@ func TestPutLockErrors(t *testing.T) { headers[api.AmzObjectLockRetainUntilDate] = "dummy" putObjectWithLockFailed(t, hc, bktName, objName, headers, apiErrors.ErrInvalidRetentionDate) - putObject(t, hc, bktName, objName) + putObject(hc, bktName, objName) retention := &data.Retention{Mode: governanceMode} putObjectRetentionFailed(t, hc, bktName, objName, retention, apiErrors.ErrMalformedXML) diff --git a/api/handler/put_test.go b/api/handler/put_test.go index c07c2700..1e21047d 100644 --- a/api/handler/put_test.go +++ b/api/handler/put_test.go @@ -23,6 +23,7 @@ import ( "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/stretchr/testify/require" ) @@ -309,3 +310,37 @@ func TestCreateBucket(t *testing.T) { box2, _ := createAccessBox(t) createBucketAssertS3Error(hc, bktName, box2, s3errors.ErrBucketAlreadyExists) } + +func TestPutObjectClientCut(t *testing.T) { + hc := prepareHandlerContext(t) + bktName, objName1, objName2 := "bkt-name", "obj-name1", "obj-name2" + createTestBucket(hc, bktName) + + putObject(hc, bktName, objName1) + obj1 := getObjectFromLayer(hc, objName1)[0] + require.Empty(t, getObjectAttribute(obj1, "s3-client-cut")) + + hc.layerFeatures.SetClientCut(true) + putObject(hc, bktName, objName2) + obj2 := getObjectFromLayer(hc, objName2)[0] + require.Equal(t, "true", getObjectAttribute(obj2, "s3-client-cut")) +} + +func getObjectFromLayer(hc *handlerContext, objName string) []*object.Object { + var res []*object.Object + for _, o := range hc.tp.Objects() { + if objName == getObjectAttribute(o, object.AttributeFilePath) { + res = append(res, o) + } + } + return res +} + +func getObjectAttribute(obj *object.Object, attrName string) string { + for _, attr := range obj.Attributes() { + if attr.Key() == attrName { + return attr.Value() + } + } + return "" +} diff --git a/api/layer/frostfs_mock.go b/api/layer/frostfs_mock.go index e550cd85..32eac88b 100644 --- a/api/layer/frostfs_mock.go +++ b/api/layer/frostfs_mock.go @@ -25,6 +25,18 @@ import ( "github.com/nspcc-dev/neo-go/pkg/crypto/keys" ) +type FeatureSettingsMock struct { + clientCut bool +} + +func (k *FeatureSettingsMock) ClientCut() bool { + return k.clientCut +} + +func (k *FeatureSettingsMock) SetClientCut(clientCut bool) { + k.clientCut = clientCut +} + type TestFrostFS struct { FrostFS @@ -222,6 +234,13 @@ func (t *TestFrostFS) CreateObject(_ context.Context, prm PrmObjectCreate) (oid. attrs = append(attrs, *a) } + if prm.ClientCut { + a := object.NewAttribute() + a.SetKey("s3-client-cut") + a.SetValue("true") + attrs = append(attrs, *a) + } + for i := range prm.Attributes { a := object.NewAttribute() a.SetKey(prm.Attributes[i][0]) diff --git a/api/layer/versioning_test.go b/api/layer/versioning_test.go index 897c9883..4476978d 100644 --- a/api/layer/versioning_test.go +++ b/api/layer/versioning_test.go @@ -170,6 +170,7 @@ func prepareContext(t *testing.T, cachesConfig ...*CachesConfig) *testContext { Caches: config, AnonKey: AnonymousKey{Key: key}, TreeService: NewTreeService(), + Features: &FeatureSettingsMock{}, } return &testContext{