diff --git a/backend/posix/posix.go b/backend/posix/posix.go index c5c80d06..dc7a3722 100644 --- a/backend/posix/posix.go +++ b/backend/posix/posix.go @@ -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) { diff --git a/tests/integration/group-tests.go b/tests/integration/group-tests.go index 361de814..6f4b73e3 100644 --- a/tests/integration/group-tests.go +++ b/tests/integration/group-tests.go @@ -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, diff --git a/tests/integration/versioning.go b/tests/integration/versioning.go index 8fdfcb19..c6402fec 100644 --- a/tests/integration/versioning.go +++ b/tests/integration/versioning.go @@ -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 {