Files
versitygw/tests/integration/ListObjectVersions.go
niksis02 d05f25f277 feat: refactoring of the integration tests
All the integration tests used to be in a single file, which had become large, messy, and difficult to maintain. These changes split `tests.go` into multiple files, organized by logical test groups.
2025-10-31 20:53:55 +04:00

471 lines
14 KiB
Go

// Copyright 2023 Versity Software
// This file is licensed under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package integration
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/versity/versitygw/s3err"
)
func ListObjectVersions_VD_success(s *S3Conf) error {
testName := "ListObjectVersions_VD_success"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
versions := []types.ObjectVersion{}
for i := range 5 {
dLgth := int64(i * 100)
key := fmt.Sprintf("my-obj-%v", i)
out, err := putObjectWithData(dLgth, &s3.PutObjectInput{
Bucket: &bucket,
Key: &key,
}, s3client)
if err != nil {
return err
}
versions = append(versions, types.ObjectVersion{
ETag: out.res.ETag,
IsLatest: getBoolPtr(true),
Key: &key,
Size: &dLgth,
VersionId: getPtr("null"),
StorageClass: types.ObjectVersionStorageClassStandard,
})
}
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
res, err := s3client.ListObjectVersions(ctx, &s3.ListObjectVersionsInput{
Bucket: &bucket,
})
cancel()
if err != nil {
return err
}
if !compareVersions(versions, res.Versions) {
return fmt.Errorf("expected object versions output to be %v, instead got %v",
versions, res.Versions)
}
return nil
})
}
func ListObjectVersions_non_existing_bucket(s *S3Conf) error {
testName := "ListObjectVersions_non_existing_bucket"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
_, err := s3client.ListObjectVersions(ctx, &s3.ListObjectVersionsInput{
Bucket: getPtr(getBucketName()),
})
cancel()
if err := checkApiErr(err, s3err.GetAPIError(s3err.ErrNoSuchBucket)); err != nil {
return err
}
return nil
}, withVersioning(types.BucketVersioningStatusEnabled))
}
func ListObjectVersions_list_single_object_versions(s *S3Conf) error {
testName := "ListObjectVersions_list_single_object_versions"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
object := "my-obj"
versions, err := createObjVersions(s3client, bucket, object, 5)
if err != nil {
return err
}
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
out, err := s3client.ListObjectVersions(ctx, &s3.ListObjectVersionsInput{
Bucket: &bucket,
})
cancel()
if err != nil {
return err
}
if !compareVersions(versions, out.Versions) {
return fmt.Errorf("expected the resulting versions to be %v, instead got %v",
versions, out.Versions)
}
return nil
}, withVersioning(types.BucketVersioningStatusEnabled))
}
func ListObjectVersions_list_multiple_object_versions(s *S3Conf) error {
testName := "ListObjectVersions_list_multiple_object_versions"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
obj1, obj2, obj3 := "foo", "bar", "baz"
obj1Versions, err := createObjVersions(s3client, bucket, obj1, 4)
if err != nil {
return err
}
obj2Versions, err := createObjVersions(s3client, bucket, obj2, 3)
if err != nil {
return err
}
obj3Versions, err := createObjVersions(s3client, bucket, obj3, 5)
if err != nil {
return err
}
versions := append(append(obj2Versions, obj3Versions...), obj1Versions...)
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
out, err := s3client.ListObjectVersions(ctx, &s3.ListObjectVersionsInput{
Bucket: &bucket,
})
cancel()
if err != nil {
return err
}
if !compareVersions(versions, out.Versions) {
return fmt.Errorf("expected the resulting versions to be %v, instead got %v",
versions, out.Versions)
}
return nil
}, withVersioning(types.BucketVersioningStatusEnabled))
}
func ListObjectVersions_multiple_object_versions_truncated(s *S3Conf) error {
testName := "ListObjectVersions_multiple_object_versions_truncated"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
obj1, obj2, obj3 := "foo", "bar", "baz"
obj1Versions, err := createObjVersions(s3client, bucket, obj1, 4)
if err != nil {
return err
}
obj2Versions, err := createObjVersions(s3client, bucket, obj2, 3)
if err != nil {
return err
}
obj3Versions, err := createObjVersions(s3client, bucket, obj3, 5)
if err != nil {
return err
}
versions := append(append(obj2Versions, obj3Versions...), obj1Versions...)
maxKeys := int32(5)
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
out, err := s3client.ListObjectVersions(ctx, &s3.ListObjectVersionsInput{
Bucket: &bucket,
MaxKeys: &maxKeys,
})
cancel()
if err != nil {
return err
}
if out.Name == nil {
return fmt.Errorf("expected the bucket name to be %v, instead got nil",
bucket)
}
if *out.Name != bucket {
return fmt.Errorf("expected the bucket name to be %v, instead got %v",
bucket, *out.Name)
}
if out.IsTruncated == nil || !*out.IsTruncated {
return fmt.Errorf("expected the output to be truncated")
}
if out.MaxKeys == nil {
return fmt.Errorf("expected the max-keys to be %v, instead got nil",
maxKeys)
}
if *out.MaxKeys != maxKeys {
return fmt.Errorf("expected the max-keys to be %v, instead got %v",
maxKeys, *out.MaxKeys)
}
if getString(out.NextKeyMarker) != getString(versions[maxKeys-1].Key) {
return fmt.Errorf("expected the NextKeyMarker to be %v, instead got %v",
getString(versions[maxKeys-1].Key), getString(out.NextKeyMarker))
}
if getString(out.NextVersionIdMarker) != getString(versions[maxKeys-1].VersionId) {
return fmt.Errorf("expected the NextVersionIdMarker to be %v, instead got %v",
getString(versions[maxKeys-1].VersionId), getString(out.NextVersionIdMarker))
}
if !compareVersions(versions[:maxKeys], out.Versions) {
return fmt.Errorf("expected the resulting object versions to be %v, instead got %v",
sprintVersions(versions[:maxKeys]), sprintVersions(out.Versions))
}
ctx, cancel = context.WithTimeout(context.Background(), shortTimeout)
out, err = s3client.ListObjectVersions(ctx, &s3.ListObjectVersionsInput{
Bucket: &bucket,
KeyMarker: out.NextKeyMarker,
VersionIdMarker: out.NextVersionIdMarker,
})
cancel()
if err != nil {
return err
}
if out.Name == nil {
return fmt.Errorf("expected the bucket name to be %v, instead got nil",
bucket)
}
if *out.Name != bucket {
return fmt.Errorf("expected the bucket name to be %v, instead got %v",
bucket, *out.Name)
}
if out.IsTruncated != nil && *out.IsTruncated {
return fmt.Errorf("expected the output not to be truncated")
}
if getString(out.KeyMarker) != getString(versions[maxKeys-1].Key) {
return fmt.Errorf("expected the KeyMarker to be %v, instead got %v",
getString(versions[maxKeys-1].Key), getString(out.KeyMarker))
}
if getString(out.VersionIdMarker) != getString(versions[maxKeys-1].VersionId) {
return fmt.Errorf("expected the VersionIdMarker to be %v, instead got %v",
getString(versions[maxKeys-1].VersionId), getString(out.VersionIdMarker))
}
if !compareVersions(versions[maxKeys:], out.Versions) {
return fmt.Errorf("expected the resulting object versions to be %v, instead got %v",
sprintVersions(versions[:maxKeys]), sprintVersions(out.Versions))
}
return nil
}, withVersioning(types.BucketVersioningStatusEnabled))
}
func ListObjectVersions_with_delete_markers(s *S3Conf) error {
testName := "ListObjectVersions_with_delete_markers"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
obj := "my-obj"
versions, err := createObjVersions(s3client, bucket, obj, 1)
if err != nil {
return err
}
versions[0].IsLatest = getBoolPtr(false)
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
out, err := s3client.DeleteObject(ctx, &s3.DeleteObjectInput{
Bucket: &bucket,
Key: &obj,
})
cancel()
if err != nil {
return err
}
delMarkers := []types.DeleteMarkerEntry{}
delMarkers = append(delMarkers, types.DeleteMarkerEntry{
Key: &obj,
VersionId: out.VersionId,
IsLatest: getBoolPtr(true),
})
ctx, cancel = context.WithTimeout(context.Background(), shortTimeout)
res, err := s3client.ListObjectVersions(ctx, &s3.ListObjectVersionsInput{
Bucket: &bucket,
})
cancel()
if err != nil {
return err
}
if !compareVersions(versions, res.Versions) {
return fmt.Errorf("expected the resulting versions to be %v, instead got %v",
versions, res.Versions)
}
if !compareDelMarkers(res.DeleteMarkers, delMarkers) {
return fmt.Errorf("expected the resulting delete markers to be %v, instead got %v",
delMarkers, res.DeleteMarkers)
}
return nil
}, withVersioning(types.BucketVersioningStatusEnabled))
}
func ListObjectVersions_containing_null_versionId_obj(s *S3Conf) error {
testName := "ListObjectVersions_containing_null_versionId_obj"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
obj := "my-obj"
versions, err := createObjVersions(s3client, bucket, obj, 3)
if err != nil {
return err
}
err = putBucketVersioningStatus(s3client, bucket, types.BucketVersioningStatusSuspended)
if err != nil {
return err
}
objLgth := int64(543)
out, err := putObjectWithData(objLgth, &s3.PutObjectInput{
Bucket: &bucket,
Key: &obj,
}, s3client)
if err != nil {
return err
}
if getString(out.res.VersionId) != nullVersionId {
return fmt.Errorf("expected the uploaded object versionId to be %v, instead got %v",
nullVersionId, getString(out.res.VersionId))
}
versions[0].IsLatest = getBoolPtr(false)
versions = append([]types.ObjectVersion{
{
ETag: out.res.ETag,
IsLatest: getBoolPtr(false),
Key: &obj,
Size: &objLgth,
VersionId: &nullVersionId,
StorageClass: types.ObjectVersionStorageClassStandard,
},
}, versions...)
err = putBucketVersioningStatus(s3client, bucket, types.BucketVersioningStatusEnabled)
if err != nil {
return err
}
newVersions, err := createObjVersions(s3client, bucket, obj, 4)
if err != nil {
return err
}
versions = append(newVersions, versions...)
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
res, err := s3client.ListObjectVersions(ctx, &s3.ListObjectVersionsInput{
Bucket: &bucket,
})
cancel()
if err != nil {
return err
}
if !compareVersions(versions, res.Versions) {
return fmt.Errorf("expected the listed object versions to be %v, instead got %v",
versions, res.Versions)
}
return nil
}, withVersioning(types.BucketVersioningStatusEnabled))
}
func ListObjectVersions_single_null_versionId_object(s *S3Conf) error {
testName := "ListObjectVersions_single_null_versionId_object"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
obj, objLgth := "my-obj", int64(890)
out, err := putObjectWithData(objLgth, &s3.PutObjectInput{
Bucket: &bucket,
Key: &obj,
}, s3client)
if err != nil {
return err
}
err = putBucketVersioningStatus(s3client, bucket, types.BucketVersioningStatusEnabled)
if err != nil {
return err
}
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
res, err := s3client.DeleteObject(ctx, &s3.DeleteObjectInput{
Bucket: &bucket,
Key: &obj,
})
cancel()
if err != nil {
return err
}
versions := []types.ObjectVersion{
{
ETag: out.res.ETag,
Key: &obj,
StorageClass: types.ObjectVersionStorageClassStandard,
IsLatest: getBoolPtr(false),
Size: &objLgth,
VersionId: &nullVersionId,
},
}
delMarkers := []types.DeleteMarkerEntry{
{
IsLatest: getBoolPtr(true),
Key: &obj,
VersionId: 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 !compareDelMarkers(resp.DeleteMarkers, delMarkers) {
return fmt.Errorf("expected the delete markers list to be %v, instaed got %v",
delMarkers, resp.DeleteMarkers)
}
if !compareVersions(versions, resp.Versions) {
return fmt.Errorf("expected the object versions list to be %v, instead got %v",
versions, resp.Versions)
}
return nil
})
}
func ListObjectVersions_checksum(s *S3Conf) error {
testName := "ListObjectVersions_checksum"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
versions := []types.ObjectVersion{}
for i, algo := range types.ChecksumAlgorithmCrc32.Values() {
vers, err := createObjVersions(s3client, bucket, fmt.Sprintf("obj-%v", i), 1, withChecksumAlgo(algo))
if err != nil {
return err
}
versions = append(versions, vers...)
}
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
res, err := s3client.ListObjectVersions(ctx, &s3.ListObjectVersionsInput{
Bucket: &bucket,
})
cancel()
if err != nil {
return err
}
if !compareVersions(versions, res.Versions) {
return fmt.Errorf("expected the versions to be %+v, instead got %+v",
versions, res.Versions)
}
return nil
}, withVersioning(types.BucketVersioningStatusEnabled))
}