You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

135 lines
4.2 KiB

package delete
import (
"bytes"
"context"
"errors"
"testing"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/aws/smithy-go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestConditionalDeleteIfMatchOnLatestVersion(t *testing.T) {
client := getTestClient(t)
bucket := createTestBucket(t, client)
defer cleanupBucket(t, client, bucket)
key := "conditional-delete.txt"
putResp, err := client.PutObject(context.TODO(), &s3.PutObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
Body: bytes.NewReader([]byte("versioned body")),
})
require.NoError(t, err)
require.NotNil(t, putResp.ETag)
_, err = client.DeleteObject(context.TODO(), &s3.DeleteObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
IfMatch: aws.String(`"not-the-current-etag"`),
})
require.Error(t, err, "DeleteObject should reject a mismatched If-Match header")
var apiErr smithy.APIError
if assert.True(t, errors.As(err, &apiErr), "Expected smithy API error for conditional delete") {
assert.Equal(t, "PreconditionFailed", apiErr.ErrorCode())
}
_, err = client.HeadObject(context.TODO(), &s3.HeadObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
})
require.NoError(t, err, "Object should remain current after a failed conditional delete")
deleteResp, err := client.DeleteObject(context.TODO(), &s3.DeleteObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
IfMatch: putResp.ETag,
})
require.NoError(t, err)
require.NotNil(t, deleteResp.DeleteMarker)
assert.True(t, *deleteResp.DeleteMarker, "Successful conditional delete on a versioned bucket should create a delete marker")
require.NotNil(t, deleteResp.VersionId)
_, err = client.HeadObject(context.TODO(), &s3.HeadObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
})
require.Error(t, err, "Delete marker should hide the current object after a successful conditional delete")
}
func TestConditionalMultiDeletePerObjectETag(t *testing.T) {
client := getTestClient(t)
bucket := createTestBucket(t, client)
defer cleanupBucket(t, client, bucket)
okKey := "delete-ok.txt"
failKey := "delete-fail.txt"
okPutResp, err := client.PutObject(context.TODO(), &s3.PutObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(okKey),
Body: bytes.NewReader([]byte("delete me")),
})
require.NoError(t, err)
require.NotNil(t, okPutResp.ETag)
_, err = client.PutObject(context.TODO(), &s3.PutObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(failKey),
Body: bytes.NewReader([]byte("keep me")),
})
require.NoError(t, err)
deleteResp, err := client.DeleteObjects(context.TODO(), &s3.DeleteObjectsInput{
Bucket: aws.String(bucket),
Delete: &types.Delete{
Objects: []types.ObjectIdentifier{
{
Key: aws.String(okKey),
ETag: okPutResp.ETag,
},
{
Key: aws.String(failKey),
ETag: aws.String(`"mismatched-etag"`),
},
},
},
})
require.NoError(t, err)
require.Len(t, deleteResp.Deleted, 1, "One object should satisfy its ETag precondition")
require.Len(t, deleteResp.Errors, 1, "One object should report a precondition failure")
deletedKeys := make([]string, 0, len(deleteResp.Deleted))
for _, deleted := range deleteResp.Deleted {
deletedKeys = append(deletedKeys, aws.ToString(deleted.Key))
}
assert.Contains(t, deletedKeys, okKey)
var matchedError *types.Error
for i := range deleteResp.Errors {
if aws.ToString(deleteResp.Errors[i].Key) == failKey {
matchedError = &deleteResp.Errors[i]
break
}
}
if assert.NotNil(t, matchedError, "Expected error entry for failed key") {
assert.Equal(t, "PreconditionFailed", aws.ToString(matchedError.Code))
}
_, err = client.HeadObject(context.TODO(), &s3.HeadObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(okKey),
})
require.Error(t, err, "Successfully deleted key should no longer be current")
_, err = client.HeadObject(context.TODO(), &s3.HeadObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(failKey),
})
require.NoError(t, err, "Object with mismatched ETag should remain untouched")
}