Merge pull request #1759 from versity/sis/deleteobject-versionid-internal-error

fix: fixes non-existing object deletion with versionId
This commit is contained in:
Ben McClelland
2026-01-16 11:26:20 -08:00
committed by GitHub
3 changed files with 68 additions and 1 deletions

View File

@@ -3407,7 +3407,13 @@ func (p *Posix) DeleteObject(ctx context.Context, input *s3.DeleteObjectInput) (
versionPath := p.genObjVersionPath(bucket, object)
vId, err := p.meta.RetrieveAttribute(nil, bucket, object, versionIdKey)
if err != nil && !errors.Is(err, meta.ErrNoSuchKey) && !errors.Is(err, fs.ErrNotExist) {
if errors.Is(err, fs.ErrNotExist) || errors.Is(err, syscall.ENOTDIR) {
// AWS returns success if the object does not exist
return &s3.DeleteObjectOutput{
VersionId: input.VersionId,
}, nil
}
if err != nil && !errors.Is(err, meta.ErrNoSuchKey) {
return nil, fmt.Errorf("get obj versionId: %w", err)
}
if errors.Is(err, meta.ErrNoSuchKey) {

View File

@@ -1040,6 +1040,7 @@ func TestVersioning(ts *TestState) {
ts.Run(Versioning_DeleteObject_delete_a_delete_marker)
ts.Run(Versioning_Delete_null_versionId_object)
ts.Run(Versioning_DeleteObject_nested_dir_object)
ts.Run(Versioning_DeleteObject_non_existing_objects)
ts.Run(Versioning_DeleteObject_suspended)
ts.Run(Versioning_DeleteObjects_success)
ts.Run(Versioning_DeleteObjects_delete_deleteMarkers)
@@ -1749,6 +1750,7 @@ func GetIntTests() IntTests {
"Versioning_DeleteObject_delete_a_delete_marker": Versioning_DeleteObject_delete_a_delete_marker,
"Versioning_Delete_null_versionId_object": Versioning_Delete_null_versionId_object,
"Versioning_DeleteObject_nested_dir_object": Versioning_DeleteObject_nested_dir_object,
"Versioning_DeleteObject_non_existing_objects": Versioning_DeleteObject_non_existing_objects,
"Versioning_DeleteObject_suspended": Versioning_DeleteObject_suspended,
"Versioning_DeleteObjects_success": Versioning_DeleteObjects_success,
"Versioning_DeleteObjects_delete_deleteMarkers": Versioning_DeleteObjects_delete_deleteMarkers,

View File

@@ -1335,6 +1335,65 @@ func Versioning_DeleteObject_nested_dir_object(s *S3Conf) error {
}, withLock())
}
func Versioning_DeleteObject_non_existing_objects(s *S3Conf) error {
testName := "Versioning_DeleteObject_non_existing_objects"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
out, err := putObjectWithData(2, &s3.PutObjectInput{
Bucket: &bucket,
Key: getPtr("foo"),
}, s3client)
if err != nil {
return err
}
versionId := getString(out.res.VersionId)
for _, test := range []struct {
key string
versionId string
}{
{"foo/bar", "01KF2YVN948NAZ4JJR4X1AAVRA"},
{"foo/bar/baz", "01KF2YVN948NAZ4JJR4X1AAVRA"},
{"hello", "01KF2YVN948NAZ4JJR4X1AAVRA"},
{"hello/world", "01KF2YVN948NAZ4JJR4X1AAVRA"},
{"foo/bar/baz/quxx", versionId},
{"foo", versionId},
} {
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
res, err := s3client.DeleteObject(ctx, &s3.DeleteObjectInput{
Bucket: &bucket,
Key: &test.key,
VersionId: &test.versionId,
})
cancel()
if err != nil {
return err
}
if getString(res.VersionId) != test.versionId {
return fmt.Errorf("expected the versionId to be %s, instead got %s", test.versionId, getString(res.VersionId))
}
}
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
resp, err := s3client.ListObjectVersions(ctx, &s3.ListObjectVersionsInput{
Bucket: &bucket,
})
cancel()
if err != nil {
return err
}
if len(resp.Versions) != 0 {
return fmt.Errorf("expected empty object versions, instead got %v", resp.Versions)
}
if len(resp.DeleteMarkers) != 0 {
return fmt.Errorf("expected empty delete markers list, insead got %v", resp.DeleteMarkers)
}
return nil
}, withLock())
}
func Versioning_DeleteObject_suspended(s *S3Conf) error {
testName := "Versioning_DeleteObject_suspended"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {