diff --git a/backend/posix/posix.go b/backend/posix/posix.go index 37eb7eac..f437de18 100644 --- a/backend/posix/posix.go +++ b/backend/posix/posix.go @@ -2038,8 +2038,9 @@ func (p *Posix) CopyObject(ctx context.Context, input *s3.CopyObjectInput) (*s3. return &s3.CopyObjectOutput{}, s3err.GetAPIError(s3err.ErrInvalidCopyDest) } - for key := range mdmap { - err := p.meta.DeleteAttribute(dstBucket, dstObject, key) + for k := range mdmap { + err := p.meta.DeleteAttribute(dstBucket, dstObject, + fmt.Sprintf("%v.%v", metaHdr, k)) if err != nil && !errors.Is(err, meta.ErrNoSuchKey) { return nil, fmt.Errorf("delete user metadata: %w", err) } diff --git a/tests/integration/tests.go b/tests/integration/tests.go index 80b7660c..7acca091 100644 --- a/tests/integration/tests.go +++ b/tests/integration/tests.go @@ -4567,6 +4567,11 @@ func CopyObject_copy_to_itself_invalid_directive(s *S3Conf) error { func CopyObject_to_itself_with_new_metadata(s *S3Conf) error { testName := "CopyObject_to_itself_with_new_metadata" + + meta := map[string]string{ + "Hello": "World", + } + return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { obj := "my-obj" err := putObjects(s3client, []string{obj}, bucket) @@ -4575,12 +4580,41 @@ func CopyObject_to_itself_with_new_metadata(s *S3Conf) error { } ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err = s3client.CopyObject(ctx, &s3.CopyObjectInput{ - Bucket: &bucket, - Key: &obj, - CopySource: getPtr(fmt.Sprintf("%v/%v", bucket, obj)), - Metadata: map[string]string{ - "Hello": "World", - }, + Bucket: &bucket, + Key: &obj, + CopySource: getPtr(fmt.Sprintf("%v/%v", bucket, obj)), + Metadata: meta, + MetadataDirective: types.MetadataDirectiveReplace, + }) + cancel() + if err != nil { + return err + } + + ctx, cancel = context.WithTimeout(context.Background(), shortTimeout) + resp, err := s3client.HeadObject(ctx, &s3.HeadObjectInput{ + Bucket: &bucket, + Key: &obj, + }) + cancel() + if err != nil { + return err + } + + if !areMapsSame(resp.Metadata, meta) { + return fmt.Errorf("expected uploaded object metadata to be %v, instead got %v", meta, resp.Metadata) + } + + // verify updating metadata has correct meta + meta = map[string]string{ + "New": "Metadata", + } + ctx, cancel = context.WithTimeout(context.Background(), shortTimeout) + _, err = s3client.CopyObject(ctx, &s3.CopyObjectInput{ + Bucket: &bucket, + Key: &obj, + CopySource: getPtr(fmt.Sprintf("%v/%v", bucket, obj)), + Metadata: meta, MetadataDirective: types.MetadataDirectiveReplace, }) cancel() @@ -4588,6 +4622,20 @@ func CopyObject_to_itself_with_new_metadata(s *S3Conf) error { return err } + ctx, cancel = context.WithTimeout(context.Background(), shortTimeout) + resp, err = s3client.HeadObject(ctx, &s3.HeadObjectInput{ + Bucket: &bucket, + Key: &obj, + }) + cancel() + if err != nil { + return err + } + + if !areMapsSame(resp.Metadata, meta) { + return fmt.Errorf("expected uploaded object metadata to be %v, instead got %v", meta, resp.Metadata) + } + return nil }) } diff --git a/tests/integration/utils.go b/tests/integration/utils.go index c611d9b2..8c29f05f 100644 --- a/tests/integration/utils.go +++ b/tests/integration/utils.go @@ -428,12 +428,15 @@ func getPtr(str string) *string { return &str } +// mp1 needs to be the response from the server +// mp2 needs to be the expected values +// The keys from the server are always converted to lowercase func areMapsSame(mp1, mp2 map[string]string) bool { if len(mp1) != len(mp2) { return false } - for key, val := range mp1 { - if mp2[key] != val { + for key, val := range mp2 { + if mp1[strings.ToLower(key)] != val { return false } }