forked from TrueCloudLab/frostfs-s3-gw
[#196] Add tagging caching
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
987185b9e1
commit
5502fb97c3
5 changed files with 96 additions and 108 deletions
6
api/cache/buckets.go
vendored
6
api/cache/buckets.go
vendored
|
@ -71,7 +71,7 @@ func (b *BucketInfo) SettingsObjectName() string {
|
||||||
return bktVersionSettingsObject
|
return bktVersionSettingsObject
|
||||||
}
|
}
|
||||||
|
|
||||||
// SettingsObjectKey is key to use in SystemCache.
|
// SystemObjectKey is key to use in SystemCache.
|
||||||
func (b *BucketInfo) SettingsObjectKey() string {
|
func (b *BucketInfo) SystemObjectKey(obj string) string {
|
||||||
return b.Name + bktVersionSettingsObject
|
return b.Name + obj
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,11 @@ func (h *handler) PutObjectTaggingHandler(w http.ResponseWriter, r *http.Request
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = h.checkBucketOwner(r, reqInfo.BucketName); err != nil {
|
||||||
|
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
p := &layer.HeadObjectParams{
|
p := &layer.HeadObjectParams{
|
||||||
Bucket: reqInfo.BucketName,
|
Bucket: reqInfo.BucketName,
|
||||||
Object: reqInfo.ObjectName,
|
Object: reqInfo.ObjectName,
|
||||||
|
@ -56,6 +61,11 @@ func (h *handler) PutObjectTaggingHandler(w http.ResponseWriter, r *http.Request
|
||||||
func (h *handler) GetObjectTaggingHandler(w http.ResponseWriter, r *http.Request) {
|
func (h *handler) GetObjectTaggingHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
reqInfo := api.GetReqInfo(r.Context())
|
reqInfo := api.GetReqInfo(r.Context())
|
||||||
|
|
||||||
|
if err := h.checkBucketOwner(r, reqInfo.BucketName); err != nil {
|
||||||
|
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
p := &layer.HeadObjectParams{
|
p := &layer.HeadObjectParams{
|
||||||
Bucket: reqInfo.BucketName,
|
Bucket: reqInfo.BucketName,
|
||||||
Object: reqInfo.ObjectName,
|
Object: reqInfo.ObjectName,
|
||||||
|
@ -89,6 +99,11 @@ func (h *handler) DeleteObjectTaggingHandler(w http.ResponseWriter, r *http.Requ
|
||||||
VersionID: reqInfo.URL.Query().Get("versionId"),
|
VersionID: reqInfo.URL.Query().Get("versionId"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := h.checkBucketOwner(r, reqInfo.BucketName); err != nil {
|
||||||
|
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
objInfo, err := h.obj.GetObjectInfo(r.Context(), p)
|
objInfo, err := h.obj.GetObjectInfo(r.Context(), p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not get object info", reqInfo, err)
|
h.logAndSendError(w, "could not get object info", reqInfo, err)
|
||||||
|
@ -111,6 +126,11 @@ func (h *handler) PutBucketTaggingHandler(w http.ResponseWriter, r *http.Request
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = h.checkBucketOwner(r, reqInfo.BucketName); err != nil {
|
||||||
|
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err := h.obj.PutBucketTagging(r.Context(), reqInfo.BucketName, tagSet); err != nil {
|
if err := h.obj.PutBucketTagging(r.Context(), reqInfo.BucketName, tagSet); err != nil {
|
||||||
h.logAndSendError(w, "could not put object tagging", reqInfo, err)
|
h.logAndSendError(w, "could not put object tagging", reqInfo, err)
|
||||||
}
|
}
|
||||||
|
@ -119,6 +139,11 @@ func (h *handler) PutBucketTaggingHandler(w http.ResponseWriter, r *http.Request
|
||||||
func (h *handler) GetBucketTaggingHandler(w http.ResponseWriter, r *http.Request) {
|
func (h *handler) GetBucketTaggingHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
reqInfo := api.GetReqInfo(r.Context())
|
reqInfo := api.GetReqInfo(r.Context())
|
||||||
|
|
||||||
|
if err := h.checkBucketOwner(r, reqInfo.BucketName); err != nil {
|
||||||
|
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
tagSet, err := h.obj.GetBucketTagging(r.Context(), reqInfo.BucketName)
|
tagSet, err := h.obj.GetBucketTagging(r.Context(), reqInfo.BucketName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logAndSendError(w, "could not get object tagging", reqInfo, err)
|
h.logAndSendError(w, "could not get object tagging", reqInfo, err)
|
||||||
|
@ -132,6 +157,10 @@ func (h *handler) GetBucketTaggingHandler(w http.ResponseWriter, r *http.Request
|
||||||
|
|
||||||
func (h *handler) DeleteBucketTaggingHandler(w http.ResponseWriter, r *http.Request) {
|
func (h *handler) DeleteBucketTaggingHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
reqInfo := api.GetReqInfo(r.Context())
|
reqInfo := api.GetReqInfo(r.Context())
|
||||||
|
if err := h.checkBucketOwner(r, reqInfo.BucketName); err != nil {
|
||||||
|
h.logAndSendError(w, "expected owner doesn't match", reqInfo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
if err := h.obj.DeleteBucketTagging(r.Context(), reqInfo.BucketName); err != nil {
|
if err := h.obj.DeleteBucketTagging(r.Context(), reqInfo.BucketName); err != nil {
|
||||||
h.logAndSendError(w, "could not delete object tagging", reqInfo, err)
|
h.logAndSendError(w, "could not delete object tagging", reqInfo, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -348,28 +348,6 @@ func (n *layer) GetObjectInfo(ctx context.Context, p *HeadObjectParams) (*Object
|
||||||
return n.headVersion(ctx, bkt, p.VersionID)
|
return n.headVersion(ctx, bkt, p.VersionID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *layer) getSettingsObjectInfo(ctx context.Context, bkt *cache.BucketInfo) (*ObjectInfo, error) {
|
|
||||||
if meta := n.systemCache.Get(bkt.SettingsObjectKey()); meta != nil {
|
|
||||||
return objInfoFromMeta(bkt, meta), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
oid, err := n.objectFindID(ctx, &findParams{cid: bkt.CID, attr: objectSystemAttributeName, val: bkt.SettingsObjectName()})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
meta, err := n.objectHead(ctx, bkt.CID, oid)
|
|
||||||
if err != nil {
|
|
||||||
n.log.Error("could not fetch object head", zap.Error(err))
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err = n.systemCache.Put(bkt.SettingsObjectKey(), meta); err != nil {
|
|
||||||
n.log.Error("couldn't cache system object", zap.Error(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
return objInfoFromMeta(bkt, meta), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PutObject into storage.
|
// PutObject into storage.
|
||||||
func (n *layer) PutObject(ctx context.Context, p *PutObjectParams) (*ObjectInfo, error) {
|
func (n *layer) PutObject(ctx context.Context, p *PutObjectParams) (*ObjectInfo, error) {
|
||||||
bkt, err := n.GetBucketInfo(ctx, p.Bucket)
|
bkt, err := n.GetBucketInfo(ctx, p.Bucket)
|
||||||
|
@ -458,19 +436,30 @@ func (n *layer) PutBucketTagging(ctx context.Context, bucketName string, tagSet
|
||||||
|
|
||||||
// DeleteObjectTagging from storage.
|
// DeleteObjectTagging from storage.
|
||||||
func (n *layer) DeleteObjectTagging(ctx context.Context, p *ObjectInfo) error {
|
func (n *layer) DeleteObjectTagging(ctx context.Context, p *ObjectInfo) error {
|
||||||
return n.deleteSystemObject(ctx, p.CID(), p.TagsObject())
|
bktInfo, err := n.GetBucketInfo(ctx, p.Bucket)
|
||||||
}
|
|
||||||
|
|
||||||
func (n *layer) deleteSystemObject(ctx context.Context, bktCID *cid.ID, name string) error {
|
|
||||||
oid, err := n.objectFindID(ctx, &findParams{cid: bktCID, attr: objectSystemAttributeName, val: name})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.IsS3Error(err, errors.ErrNoSuchKey) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
return n.deleteSystemObject(ctx, bktInfo, p.TagsObject())
|
||||||
|
}
|
||||||
|
|
||||||
return n.objectDelete(ctx, bktCID, oid)
|
func (n *layer) deleteSystemObject(ctx context.Context, bktInfo *cache.BucketInfo, name string) error {
|
||||||
|
var oid *object.ID
|
||||||
|
if meta := n.systemCache.Get(bktInfo.SystemObjectKey(name)); meta != nil {
|
||||||
|
oid = meta.ID()
|
||||||
|
} else {
|
||||||
|
var err error
|
||||||
|
oid, err = n.objectFindID(ctx, &findParams{cid: bktInfo.CID, attr: objectSystemAttributeName, val: name})
|
||||||
|
if err != nil {
|
||||||
|
if errors.IsS3Error(err, errors.ErrNoSuchKey) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n.systemCache.Delete(bktInfo.SystemObjectKey(name))
|
||||||
|
return n.objectDelete(ctx, bktInfo.CID, oid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteBucketTagging from storage.
|
// DeleteBucketTagging from storage.
|
||||||
|
@ -480,13 +469,21 @@ func (n *layer) DeleteBucketTagging(ctx context.Context, bucketName string) erro
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return n.deleteSystemObject(ctx, bktInfo.CID, formBucketTagObjectName(bucketName))
|
return n.deleteSystemObject(ctx, bktInfo, formBucketTagObjectName(bucketName))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *layer) putSystemObject(ctx context.Context, bktInfo *cache.BucketInfo, objName string, metadata map[string]string, prefix string) (*object.ID, error) {
|
func (n *layer) putSystemObject(ctx context.Context, bktInfo *cache.BucketInfo, objName string, metadata map[string]string, prefix string) (*object.Object, error) {
|
||||||
oldOID, err := n.objectFindID(ctx, &findParams{cid: bktInfo.CID, attr: objectSystemAttributeName, val: objName})
|
var (
|
||||||
if err != nil && !errors.IsS3Error(err, errors.ErrNoSuchKey) {
|
err error
|
||||||
return nil, err
|
oldOID *object.ID
|
||||||
|
)
|
||||||
|
if meta := n.systemCache.Get(bktInfo.SystemObjectKey(objName)); meta != nil {
|
||||||
|
oldOID = meta.ID()
|
||||||
|
} else {
|
||||||
|
oldOID, err = n.objectFindID(ctx, &findParams{cid: bktInfo.CID, attr: objectSystemAttributeName, val: objName})
|
||||||
|
if err != nil && !errors.IsS3Error(err, errors.ErrNoSuchKey) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes := make([]*object.Attribute, 0, 3)
|
attributes := make([]*object.Attribute, 0, 3)
|
||||||
|
@ -526,19 +523,27 @@ func (n *layer) putSystemObject(ctx context.Context, bktInfo *cache.BucketInfo,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = n.objectHead(ctx, bktInfo.CID, oid); err != nil {
|
meta, err := n.objectHead(ctx, bktInfo.CID, oid)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if err = n.systemCache.Put(bktInfo.SystemObjectKey(objName), meta); err != nil {
|
||||||
|
n.log.Error("couldn't cache system object", zap.Error(err))
|
||||||
|
}
|
||||||
if oldOID != nil {
|
if oldOID != nil {
|
||||||
if err = n.objectDelete(ctx, bktInfo.CID, oldOID); err != nil {
|
if err = n.objectDelete(ctx, bktInfo.CID, oldOID); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return oid, nil
|
return meta, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *layer) getSystemObject(ctx context.Context, bkt *cache.BucketInfo, objName string) (*ObjectInfo, error) {
|
func (n *layer) getSystemObject(ctx context.Context, bkt *cache.BucketInfo, objName string) (*ObjectInfo, error) {
|
||||||
|
if meta := n.systemCache.Get(bkt.SystemObjectKey(objName)); meta != nil {
|
||||||
|
return objInfoFromMeta(bkt, meta), nil
|
||||||
|
}
|
||||||
|
|
||||||
oid, err := n.objectFindID(ctx, &findParams{cid: bkt.CID, attr: objectSystemAttributeName, val: objName})
|
oid, err := n.objectFindID(ctx, &findParams{cid: bkt.CID, attr: objectSystemAttributeName, val: objName})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -548,8 +553,11 @@ func (n *layer) getSystemObject(ctx context.Context, bkt *cache.BucketInfo, objN
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if err = n.systemCache.Put(bkt.SystemObjectKey(objName), meta); err != nil {
|
||||||
|
n.log.Error("couldn't cache system object", zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
return objectInfoFromMeta(bkt, meta, "", ""), nil
|
return objInfoFromMeta(bkt, meta), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CopyObject from one bucket into another bucket.
|
// CopyObject from one bucket into another bucket.
|
||||||
|
@ -619,7 +627,7 @@ func (n *layer) deleteObject(ctx context.Context, bkt *cache.BucketInfo, obj *Ve
|
||||||
if err = n.objectDelete(ctx, bkt.CID, id); err != nil {
|
if err = n.objectDelete(ctx, bkt.CID, id); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = n.DeleteObjectTagging(ctx, &ObjectInfo{id: id, bucketID: bkt.CID, Name: obj.Name}); err != nil {
|
if err = n.DeleteObjectTagging(ctx, &ObjectInfo{id: id, Bucket: bkt.Name, Name: obj.Name}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,10 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/pkg/client"
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/pkg/object"
|
"github.com/nspcc-dev/neofs-api-go/pkg/object"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api/cache"
|
"github.com/nspcc-dev/neofs-s3-gw/api/cache"
|
||||||
"github.com/nspcc-dev/neofs-s3-gw/api/errors"
|
"github.com/nspcc-dev/neofs-s3-gw/api/errors"
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type objectVersions struct {
|
type objectVersions struct {
|
||||||
|
@ -120,68 +117,22 @@ func (v *objectVersions) getVersion(oid *object.ID) *ObjectInfo {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *layer) PutBucketVersioning(ctx context.Context, p *PutVersioningParams) (*ObjectInfo, error) {
|
func (n *layer) PutBucketVersioning(ctx context.Context, p *PutVersioningParams) (*ObjectInfo, error) {
|
||||||
bucketInfo, err := n.GetBucketInfo(ctx, p.Bucket)
|
bktInfo, err := n.GetBucketInfo(ctx, p.Bucket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
objectInfo, err := n.getSettingsObjectInfo(ctx, bucketInfo)
|
metadata := map[string]string{
|
||||||
if err != nil {
|
attrSettingsVersioningEnabled: strconv.FormatBool(p.Settings.VersioningEnabled),
|
||||||
n.log.Warn("couldn't get bucket version settings object, new one will be created",
|
|
||||||
zap.String("bucket_name", bucketInfo.Name),
|
|
||||||
zap.Stringer("cid", bucketInfo.CID),
|
|
||||||
zap.Error(err))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes := make([]*object.Attribute, 0, 3)
|
meta, err := n.putSystemObject(ctx, bktInfo, bktInfo.SettingsObjectName(), metadata, "")
|
||||||
|
|
||||||
filename := object.NewAttribute()
|
|
||||||
filename.SetKey(objectSystemAttributeName)
|
|
||||||
filename.SetValue(bucketInfo.SettingsObjectName())
|
|
||||||
|
|
||||||
createdAt := object.NewAttribute()
|
|
||||||
createdAt.SetKey(object.AttributeTimestamp)
|
|
||||||
createdAt.SetValue(strconv.FormatInt(time.Now().UTC().Unix(), 10))
|
|
||||||
|
|
||||||
versioningIgnore := object.NewAttribute()
|
|
||||||
versioningIgnore.SetKey(attrVersionsIgnore)
|
|
||||||
versioningIgnore.SetValue(strconv.FormatBool(true))
|
|
||||||
|
|
||||||
settingsVersioningEnabled := object.NewAttribute()
|
|
||||||
settingsVersioningEnabled.SetKey(attrSettingsVersioningEnabled)
|
|
||||||
settingsVersioningEnabled.SetValue(strconv.FormatBool(p.Settings.VersioningEnabled))
|
|
||||||
|
|
||||||
attributes = append(attributes, filename, createdAt, versioningIgnore, settingsVersioningEnabled)
|
|
||||||
|
|
||||||
raw := object.NewRaw()
|
|
||||||
raw.SetOwnerID(bucketInfo.Owner)
|
|
||||||
raw.SetContainerID(bucketInfo.CID)
|
|
||||||
raw.SetAttributes(attributes...)
|
|
||||||
|
|
||||||
ops := new(client.PutObjectParams).WithObject(raw.Object())
|
|
||||||
oid, err := n.pool.PutObject(ctx, ops, n.BearerOpt(ctx))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
meta, err := n.objectHead(ctx, bucketInfo.CID, oid)
|
return objInfoFromMeta(bktInfo, meta), nil
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = n.systemCache.Put(bucketInfo.SettingsObjectKey(), meta); err != nil {
|
|
||||||
n.log.Error("couldn't cache system object", zap.Error(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
if objectInfo != nil {
|
|
||||||
if err = n.objectDelete(ctx, bucketInfo.CID, objectInfo.ID()); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return objectInfoFromMeta(bucketInfo, meta, "", ""), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *layer) GetBucketVersioning(ctx context.Context, bucketName string) (*BucketSettings, error) {
|
func (n *layer) GetBucketVersioning(ctx context.Context, bucketName string) (*BucketSettings, error) {
|
||||||
|
@ -296,7 +247,7 @@ func contains(list []string, elem string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *layer) getBucketSettings(ctx context.Context, bktInfo *cache.BucketInfo) (*BucketSettings, error) {
|
func (n *layer) getBucketSettings(ctx context.Context, bktInfo *cache.BucketInfo) (*BucketSettings, error) {
|
||||||
objInfo, err := n.getSettingsObjectInfo(ctx, bktInfo)
|
objInfo, err := n.getSystemObject(ctx, bktInfo, bktInfo.SettingsObjectName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -359,21 +359,21 @@ Compatibility: 0/19/22
|
||||||
|
|
||||||
## Tagging
|
## Tagging
|
||||||
|
|
||||||
Compatibility: 0/8/11
|
Compatibility: 9/8/11
|
||||||
|
|
||||||
| | Test | s3-gw | aws s3 |
|
| | Test | s3-gw | aws s3 |
|
||||||
|----|------------------------------------------------------------|-------|--------|
|
|----|------------------------------------------------------------|-------|--------|
|
||||||
| 1 | s3tests_boto3.functional.test_s3.test_set_bucket_tagging | FAIL | FAIL |
|
| 1 | s3tests_boto3.functional.test_s3.test_set_bucket_tagging | FAIL | FAIL |
|
||||||
| 2 | s3tests_boto3.functional.test_s3.test_get_obj_tagging | ERROR | ok |
|
| 2 | s3tests_boto3.functional.test_s3.test_get_obj_tagging | ok | ok |
|
||||||
| 3 | s3tests_boto3.functional.test_s3.test_get_obj_head_tagging | ERROR | ok |
|
| 3 | s3tests_boto3.functional.test_s3.test_get_obj_head_tagging | ok | ok |
|
||||||
| 4 | s3tests_boto3.functional.test_s3.test_put_max_tags | ERROR | ok |
|
| 4 | s3tests_boto3.functional.test_s3.test_put_max_tags | ok | ok |
|
||||||
| 5 | s3tests_boto3.functional.test_s3.test_put_excess_tags | FAIL | FAIL |
|
| 5 | s3tests_boto3.functional.test_s3.test_put_excess_tags | FAIL | FAIL |
|
||||||
| 6 | s3tests_boto3.functional.test_s3.test_put_max_kvsize_tags | ERROR | ok |
|
| 6 | s3tests_boto3.functional.test_s3.test_put_max_kvsize_tags | ok | ok |
|
||||||
| 7 | s3tests_boto3.functional.test_s3.test_put_excess_key_tags | FAIL | ok |
|
| 7 | s3tests_boto3.functional.test_s3.test_put_excess_key_tags | ok | ok |
|
||||||
| 8 | s3tests_boto3.functional.test_s3.test_put_excess_val_tags | FAIL | ok |
|
| 8 | s3tests_boto3.functional.test_s3.test_put_excess_val_tags | ok | ok |
|
||||||
| 9 | s3tests_boto3.functional.test_s3.test_put_modify_tags | ERROR | FAIL |
|
| 9 | s3tests_boto3.functional.test_s3.test_put_modify_tags | ok | FAIL |
|
||||||
| 10 | s3tests_boto3.functional.test_s3.test_put_delete_tags | ERROR | ok |
|
| 10 | s3tests_boto3.functional.test_s3.test_put_delete_tags | ok | ok |
|
||||||
| 11 | s3tests_boto3.functional.test_s3.test_put_obj_with_tags | ERROR | ok |
|
| 11 | s3tests_boto3.functional.test_s3.test_put_obj_with_tags | ok | ok |
|
||||||
|
|
||||||
## Versioning
|
## Versioning
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue