forked from TrueCloudLab/frostfs-s3-gw
[#452] Fix versions tests
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
5529fb914e
commit
9fb3fb1274
5 changed files with 92 additions and 120 deletions
|
@ -17,7 +17,6 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api/data"
|
"github.com/nspcc-dev/neofs-s3-gw/api/data"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api/layer"
|
"github.com/nspcc-dev/neofs-s3-gw/api/layer"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api/resolver"
|
"github.com/nspcc-dev/neofs-s3-gw/api/resolver"
|
||||||
treetest "github.com/nspcc-dev/neofs-s3-gw/internal/neofstest/tree"
|
|
||||||
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/object"
|
"github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/user"
|
"github.com/nspcc-dev/neofs-sdk-go/user"
|
||||||
|
@ -59,7 +58,7 @@ func prepareHandlerContext(t *testing.T) *handlerContext {
|
||||||
Caches: layer.DefaultCachesConfigs(zap.NewExample()),
|
Caches: layer.DefaultCachesConfigs(zap.NewExample()),
|
||||||
AnonKey: layer.AnonymousKey{Key: key},
|
AnonKey: layer.AnonymousKey{Key: key},
|
||||||
Resolver: testResolver,
|
Resolver: testResolver,
|
||||||
TreeService: treetest.NewTreeService(),
|
TreeService: layer.NewTreeService(),
|
||||||
}
|
}
|
||||||
|
|
||||||
h := &handler{
|
h := &handler{
|
||||||
|
|
|
@ -499,6 +499,8 @@ func (n *layer) deleteObject(ctx context.Context, bkt *data.BucketInfo, settings
|
||||||
if obj.Error = n.treeService.AddVersion(ctx, &bkt.CID, obj.Name, newVersion); obj.Error != nil {
|
if obj.Error = n.treeService.AddVersion(ctx, &bkt.CID, obj.Name, newVersion); obj.Error != nil {
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
n.namesCache.Delete(bkt.Name + "/" + obj.Name)
|
||||||
} else {
|
} else {
|
||||||
versions, err := n.treeService.GetVersions(ctx, &bkt.CID, obj.Name)
|
versions, err := n.treeService.GetVersions(ctx, &bkt.CID, obj.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -530,16 +532,7 @@ func (n *layer) removeVersionIfFound(ctx context.Context, bkt *data.BucketInfo,
|
||||||
if err := n.objectDelete(ctx, bkt, version.OID); err != nil {
|
if err := n.objectDelete(ctx, bkt, version.OID); err != nil {
|
||||||
return deleteMarkVersion, err
|
return deleteMarkVersion, err
|
||||||
}
|
}
|
||||||
if err := n.treeService.RemoveVersion(ctx, &bkt.CID, version.ID); err != nil {
|
return deleteMarkVersion, n.treeService.RemoveVersion(ctx, &bkt.CID, version.ID)
|
||||||
return deleteMarkVersion, err
|
|
||||||
}
|
|
||||||
|
|
||||||
p := &ObjectVersion{
|
|
||||||
BktInfo: bkt,
|
|
||||||
ObjectName: obj.Name,
|
|
||||||
VersionID: version.OID.EncodeToString(),
|
|
||||||
}
|
|
||||||
return deleteMarkVersion, n.DeleteObjectTagging(ctx, p)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", errors.GetAPIError(errors.ErrNoSuchVersion)
|
return "", errors.GetAPIError(errors.ErrNoSuchVersion)
|
||||||
|
|
|
@ -342,34 +342,31 @@ func (n *layer) headVersions(ctx context.Context, bkt *data.BucketInfo, objectNa
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *layer) headVersion(ctx context.Context, bkt *data.BucketInfo, p *HeadObjectParams) (*data.ObjectInfo, error) {
|
func (n *layer) headVersion(ctx context.Context, bkt *data.BucketInfo, p *HeadObjectParams) (*data.ObjectInfo, error) {
|
||||||
|
var err error
|
||||||
|
var foundVersion *data.NodeVersion
|
||||||
if p.VersionID == unversionedObjectVersionID {
|
if p.VersionID == unversionedObjectVersionID {
|
||||||
versions, err := n.headVersions(ctx, bkt, p.Object)
|
foundVersion, err = n.treeService.GetUnversioned(ctx, &bkt.CID, p.Object)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, ErrNodeNotFound) {
|
||||||
|
return nil, apiErrors.GetAPIError(apiErrors.ErrNoSuchVersion)
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
versions, err := n.treeService.GetVersions(ctx, &bkt.CID, p.Object)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("couldn't get versions: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
objInfo := versions.getLast(FromUnversioned())
|
for _, version := range versions {
|
||||||
if objInfo == nil {
|
if version.OID.EncodeToString() == p.VersionID {
|
||||||
|
foundVersion = version
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if foundVersion == nil {
|
||||||
return nil, apiErrors.GetAPIError(apiErrors.ErrNoSuchVersion)
|
return nil, apiErrors.GetAPIError(apiErrors.ErrNoSuchVersion)
|
||||||
}
|
}
|
||||||
return objInfo, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
versions, err := n.treeService.GetVersions(ctx, &bkt.CID, p.Object)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("couldn't get versions: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var foundVersion *data.NodeVersion
|
|
||||||
for _, version := range versions {
|
|
||||||
if version.OID.EncodeToString() == p.VersionID {
|
|
||||||
foundVersion = version
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if foundVersion == nil {
|
|
||||||
return nil, apiErrors.GetAPIError(apiErrors.ErrNoSuchVersion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if headInfo := n.objCache.Get(newAddress(bkt.CID, foundVersion.OID)); headInfo != nil {
|
if headInfo := n.objCache.Get(newAddress(bkt.CID, foundVersion.OID)); headInfo != nil {
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
package tree
|
package layer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -48,8 +47,6 @@ func (t *TreeServiceMock) DeleteBucketTagging(ctx context.Context, cnrID *cid.ID
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
var ErrNodeNotFound = errors.New("not found")
|
|
||||||
|
|
||||||
func NewTreeService() *TreeServiceMock {
|
func NewTreeService() *TreeServiceMock {
|
||||||
return &TreeServiceMock{
|
return &TreeServiceMock{
|
||||||
settings: make(map[string]*data.BucketSettings),
|
settings: make(map[string]*data.BucketSettings),
|
||||||
|
@ -107,7 +104,7 @@ func (t *TreeServiceMock) GetVersions(_ context.Context, cnrID *cid.ID, objectNa
|
||||||
return versions, nil
|
return versions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TreeServiceMock) GetLatestVersion(ctx context.Context, cnrID *cid.ID, objectName string) (*data.NodeVersion, error) {
|
func (t *TreeServiceMock) GetLatestVersion(_ context.Context, cnrID *cid.ID, objectName string) (*data.NodeVersion, error) {
|
||||||
cnrVersionsMap, ok := t.versions[cnrID.EncodeToString()]
|
cnrVersionsMap, ok := t.versions[cnrID.EncodeToString()]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, ErrNodeNotFound
|
return nil, ErrNodeNotFound
|
||||||
|
@ -154,8 +151,24 @@ func (t *TreeServiceMock) GetLatestVersionsByPrefix(_ context.Context, cnrID *ci
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TreeServiceMock) GetUnversioned(ctx context.Context, cnrID *cid.ID, objectName string) (*data.NodeVersion, error) {
|
func (t *TreeServiceMock) GetUnversioned(_ context.Context, cnrID *cid.ID, objectName string) (*data.NodeVersion, error) {
|
||||||
panic("implement me")
|
cnrVersionsMap, ok := t.versions[cnrID.EncodeToString()]
|
||||||
|
if !ok {
|
||||||
|
return nil, ErrNodeNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
versions, ok := cnrVersionsMap[objectName]
|
||||||
|
if !ok {
|
||||||
|
return nil, ErrNodeNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, version := range versions {
|
||||||
|
if version.IsUnversioned {
|
||||||
|
return version, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, ErrNodeNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TreeServiceMock) AddVersion(_ context.Context, cnrID *cid.ID, objectName string, newVersion *data.NodeVersion) error {
|
func (t *TreeServiceMock) AddVersion(_ context.Context, cnrID *cid.ID, objectName string, newVersion *data.NodeVersion) error {
|
||||||
|
@ -179,6 +192,7 @@ func (t *TreeServiceMock) AddVersion(_ context.Context, cnrID *cid.ID, objectNam
|
||||||
|
|
||||||
if len(versions) != 0 {
|
if len(versions) != 0 {
|
||||||
newVersion.ID = versions[len(versions)-1].ID + 1
|
newVersion.ID = versions[len(versions)-1].ID + 1
|
||||||
|
newVersion.Timestamp = versions[len(versions)-1].Timestamp + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
result := versions
|
result := versions
|
||||||
|
@ -197,12 +211,38 @@ func (t *TreeServiceMock) AddVersion(_ context.Context, cnrID *cid.ID, objectNam
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TreeServiceMock) RemoveVersion(ctx context.Context, cnrID *cid.ID, nodeID uint64) error {
|
func (t *TreeServiceMock) RemoveVersion(_ context.Context, cnrID *cid.ID, nodeID uint64) error {
|
||||||
panic("implement me")
|
cnrVersionsMap, ok := t.versions[cnrID.EncodeToString()]
|
||||||
|
if !ok {
|
||||||
|
return ErrNodeNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, versions := range cnrVersionsMap {
|
||||||
|
for i, node := range versions {
|
||||||
|
if node.ID == nodeID {
|
||||||
|
cnrVersionsMap[key] = append(versions[:i], versions[i+1:]...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrNodeNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TreeServiceMock) GetAllVersionsByPrefix(ctx context.Context, cnrID *cid.ID, prefix string) ([]*data.NodeVersion, error) {
|
func (t *TreeServiceMock) GetAllVersionsByPrefix(_ context.Context, cnrID *cid.ID, prefix string) ([]*data.NodeVersion, error) {
|
||||||
panic("implement me")
|
cnrVersionsMap, ok := t.versions[cnrID.EncodeToString()]
|
||||||
|
if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []*data.NodeVersion
|
||||||
|
for objName, versions := range cnrVersionsMap {
|
||||||
|
if strings.HasPrefix(objName, prefix) {
|
||||||
|
result = append(result, versions...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TreeServiceMock) CreateMultipartUpload(ctx context.Context, cnrID *cid.ID, info *data.MultipartInfo) error {
|
func (t *TreeServiceMock) CreateMultipartUpload(ctx context.Context, cnrID *cid.ID, info *data.MultipartInfo) error {
|
|
@ -11,7 +11,6 @@ import (
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api"
|
"github.com/nspcc-dev/neofs-s3-gw/api"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api/data"
|
"github.com/nspcc-dev/neofs-s3-gw/api/data"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
|
"github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
|
||||||
treetest "github.com/nspcc-dev/neofs-s3-gw/internal/neofstest/tree"
|
|
||||||
bearertest "github.com/nspcc-dev/neofs-sdk-go/bearer/test"
|
bearertest "github.com/nspcc-dev/neofs-sdk-go/bearer/test"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/object"
|
"github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
||||||
|
@ -177,7 +176,7 @@ func prepareContext(t *testing.T, cachesConfig ...*CachesConfig) *testContext {
|
||||||
layerCfg := &Config{
|
layerCfg := &Config{
|
||||||
Caches: config,
|
Caches: config,
|
||||||
AnonKey: AnonymousKey{Key: key},
|
AnonKey: AnonymousKey{Key: key},
|
||||||
TreeService: treetest.NewTreeService(),
|
TreeService: NewTreeService(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return &testContext{
|
return &testContext{
|
||||||
|
@ -251,6 +250,24 @@ func TestVersioningDeleteObject(t *testing.T) {
|
||||||
tc.checkListObjects()
|
tc.checkListObjects()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetUnversioned(t *testing.T) {
|
||||||
|
tc := prepareContext(t)
|
||||||
|
|
||||||
|
objContent := []byte("content obj1 v1")
|
||||||
|
objInfo := tc.putObject(objContent)
|
||||||
|
|
||||||
|
settings := &data.BucketSettings{VersioningEnabled: false}
|
||||||
|
err := tc.layer.PutBucketSettings(tc.ctx, &PutSettingsParams{
|
||||||
|
BktInfo: tc.bktInfo,
|
||||||
|
Settings: settings,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
resInfo, buffer := tc.getObject(tc.obj, unversionedObjectVersionID, false)
|
||||||
|
require.Equal(t, objContent, buffer)
|
||||||
|
require.Equal(t, objInfo.Version(), resInfo.Version())
|
||||||
|
}
|
||||||
|
|
||||||
func TestVersioningDeleteSpecificObjectVersion(t *testing.T) {
|
func TestVersioningDeleteSpecificObjectVersion(t *testing.T) {
|
||||||
tc := prepareContext(t)
|
tc := prepareContext(t)
|
||||||
settings := &data.BucketSettings{VersioningEnabled: true}
|
settings := &data.BucketSettings{VersioningEnabled: true}
|
||||||
|
@ -521,77 +538,3 @@ func getTestObjectInfoEpoch(epoch uint64, id byte, addAttr, delAttr, delMarkAttr
|
||||||
obj.CreationEpoch = epoch
|
obj.CreationEpoch = epoch
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSystemObjectsVersioning(t *testing.T) {
|
|
||||||
cacheConfig := DefaultCachesConfigs(zap.NewExample())
|
|
||||||
cacheConfig.System.Lifetime = 0
|
|
||||||
|
|
||||||
tc := prepareContext(t, cacheConfig)
|
|
||||||
err := tc.layer.PutBucketSettings(tc.ctx, &PutSettingsParams{
|
|
||||||
BktInfo: tc.bktInfo,
|
|
||||||
Settings: &data.BucketSettings{VersioningEnabled: false},
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
objMeta := tc.getSystemObject(tc.bktInfo.SettingsObjectName())
|
|
||||||
require.NotNil(t, objMeta)
|
|
||||||
|
|
||||||
err = tc.layer.PutBucketSettings(tc.ctx, &PutSettingsParams{
|
|
||||||
BktInfo: tc.bktInfo,
|
|
||||||
Settings: &data.BucketSettings{VersioningEnabled: true},
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
cnrID, _ := objMeta.ContainerID()
|
|
||||||
objID, _ := objMeta.ID()
|
|
||||||
|
|
||||||
var addr oid.Address
|
|
||||||
addr.SetContainer(cnrID)
|
|
||||||
addr.SetObject(objID)
|
|
||||||
|
|
||||||
// simulate failed deletion
|
|
||||||
tc.testNeoFS.AddObject(addr.EncodeToString(), objMeta)
|
|
||||||
|
|
||||||
versioning, err := tc.layer.GetBucketSettings(tc.ctx, tc.bktInfo)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, versioning.VersioningEnabled)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDeleteSystemObjectsVersioning(t *testing.T) {
|
|
||||||
cacheConfig := DefaultCachesConfigs(zap.NewExample())
|
|
||||||
cacheConfig.System.Lifetime = 0
|
|
||||||
|
|
||||||
tc := prepareContext(t, cacheConfig)
|
|
||||||
|
|
||||||
tagSet := map[string]string{
|
|
||||||
"tag1": "val1",
|
|
||||||
}
|
|
||||||
|
|
||||||
err := tc.layer.PutBucketTagging(tc.ctx, &tc.bktInfo.CID, tagSet)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
objMeta := tc.getSystemObject(formBucketTagObjectName(tc.bktInfo.CID.EncodeToString()))
|
|
||||||
|
|
||||||
tagSet["tag2"] = "val2"
|
|
||||||
err = tc.layer.PutBucketTagging(tc.ctx, &tc.bktInfo.CID, tagSet)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// simulate failed deletion
|
|
||||||
cnrID, _ := objMeta.ContainerID()
|
|
||||||
objID, _ := objMeta.ID()
|
|
||||||
tc.testNeoFS.AddObject(newAddress(cnrID, objID).EncodeToString(), objMeta)
|
|
||||||
|
|
||||||
tagging, err := tc.layer.GetBucketTagging(tc.ctx, &tc.bktInfo.CID)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
expectedTagSet := map[string]string{
|
|
||||||
"tag1": "val1",
|
|
||||||
"tag2": "val2",
|
|
||||||
}
|
|
||||||
require.Equal(t, expectedTagSet, tagging)
|
|
||||||
|
|
||||||
err = tc.layer.DeleteBucketTagging(tc.ctx, &tc.bktInfo.CID)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
require.Nil(t, tc.getSystemObject(formBucketTagObjectName(tc.bktInfo.Name)))
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue