[#452] Fix versions tests

Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
Denis Kirillov 2022-05-31 11:12:53 +03:00 committed by Alex Vanin
parent 5529fb914e
commit 9fb3fb1274
5 changed files with 92 additions and 120 deletions

View file

@ -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{

View file

@ -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)

View file

@ -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 {

View file

@ -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 {

View file

@ -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)))
}