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.
169 lines
5.1 KiB
169 lines
5.1 KiB
package basic
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
"github.com/aws/aws-sdk-go/service/s3"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// TestS3ListDelimiterWithDirectoryKeyObjects tests the specific scenario from
|
|
// test_bucket_list_delimiter_not_skip_special where directory key objects
|
|
// should be properly grouped into common prefixes when using delimiters
|
|
func TestS3ListDelimiterWithDirectoryKeyObjects(t *testing.T) {
|
|
bucketName := fmt.Sprintf("test-delimiter-dir-key-%d", rand.Int31())
|
|
|
|
// Create bucket
|
|
_, err := svc.CreateBucket(&s3.CreateBucketInput{
|
|
Bucket: aws.String(bucketName),
|
|
})
|
|
require.NoError(t, err)
|
|
defer cleanupBucket(t, bucketName)
|
|
|
|
// Create objects matching the failing test scenario:
|
|
// ['0/'] + ['0/1000', '0/1001', '0/1002'] + ['1999', '1999#', '1999+', '2000']
|
|
objects := []string{
|
|
"0/", // Directory key object
|
|
"0/1000", // Objects under 0/ prefix
|
|
"0/1001",
|
|
"0/1002",
|
|
"1999", // Objects without delimiter
|
|
"1999#",
|
|
"1999+",
|
|
"2000",
|
|
}
|
|
|
|
// Create all objects
|
|
for _, key := range objects {
|
|
_, err := svc.PutObject(&s3.PutObjectInput{
|
|
Bucket: aws.String(bucketName),
|
|
Key: aws.String(key),
|
|
Body: strings.NewReader(fmt.Sprintf("content for %s", key)),
|
|
})
|
|
require.NoError(t, err, "Failed to create object %s", key)
|
|
}
|
|
|
|
// Test with delimiter='/'
|
|
resp, err := svc.ListObjects(&s3.ListObjectsInput{
|
|
Bucket: aws.String(bucketName),
|
|
Delimiter: aws.String("/"),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Extract keys and prefixes
|
|
var keys []string
|
|
for _, content := range resp.Contents {
|
|
keys = append(keys, *content.Key)
|
|
}
|
|
|
|
var prefixes []string
|
|
for _, prefix := range resp.CommonPrefixes {
|
|
prefixes = append(prefixes, *prefix.Prefix)
|
|
}
|
|
|
|
// Expected results:
|
|
// Keys should be: ['1999', '1999#', '1999+', '2000'] (objects without delimiters)
|
|
// Prefixes should be: ['0/'] (grouping '0/' and all '0/xxxx' objects)
|
|
|
|
expectedKeys := []string{"1999", "1999#", "1999+", "2000"}
|
|
expectedPrefixes := []string{"0/"}
|
|
|
|
t.Logf("Actual keys: %v", keys)
|
|
t.Logf("Actual prefixes: %v", prefixes)
|
|
|
|
assert.ElementsMatch(t, expectedKeys, keys, "Keys should only include objects without delimiters")
|
|
assert.ElementsMatch(t, expectedPrefixes, prefixes, "CommonPrefixes should group directory key object with other objects sharing prefix")
|
|
|
|
// Additional validation
|
|
assert.Equal(t, "/", *resp.Delimiter, "Delimiter should be set correctly")
|
|
assert.Contains(t, prefixes, "0/", "Directory key object '0/' should be grouped into common prefix '0/'")
|
|
assert.NotContains(t, keys, "0/", "Directory key object '0/' should NOT appear as individual key when delimiter is used")
|
|
|
|
// Verify none of the '0/xxxx' objects appear as individual keys
|
|
for _, key := range keys {
|
|
assert.False(t, strings.HasPrefix(key, "0/"), "No object with '0/' prefix should appear as individual key, found: %s", key)
|
|
}
|
|
}
|
|
|
|
// TestS3ListWithoutDelimiter tests that directory key objects appear as individual keys when no delimiter is used
|
|
func TestS3ListWithoutDelimiter(t *testing.T) {
|
|
bucketName := fmt.Sprintf("test-no-delimiter-%d", rand.Int31())
|
|
|
|
// Create bucket
|
|
_, err := svc.CreateBucket(&s3.CreateBucketInput{
|
|
Bucket: aws.String(bucketName),
|
|
})
|
|
require.NoError(t, err)
|
|
defer cleanupBucket(t, bucketName)
|
|
|
|
// Create objects
|
|
objects := []string{"0/", "0/1000", "1999"}
|
|
|
|
for _, key := range objects {
|
|
_, err := svc.PutObject(&s3.PutObjectInput{
|
|
Bucket: aws.String(bucketName),
|
|
Key: aws.String(key),
|
|
Body: strings.NewReader(fmt.Sprintf("content for %s", key)),
|
|
})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// Test without delimiter
|
|
resp, err := svc.ListObjects(&s3.ListObjectsInput{
|
|
Bucket: aws.String(bucketName),
|
|
// No delimiter specified
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Extract keys
|
|
var keys []string
|
|
for _, content := range resp.Contents {
|
|
keys = append(keys, *content.Key)
|
|
}
|
|
|
|
// When no delimiter is used, all objects should be returned as individual keys
|
|
expectedKeys := []string{"0/", "0/1000", "1999"}
|
|
assert.ElementsMatch(t, expectedKeys, keys, "All objects should be individual keys when no delimiter is used")
|
|
|
|
// No common prefixes should be present
|
|
assert.Empty(t, resp.CommonPrefixes, "No common prefixes should be present when no delimiter is used")
|
|
assert.Contains(t, keys, "0/", "Directory key object '0/' should appear as individual key when no delimiter is used")
|
|
}
|
|
|
|
func cleanupBucket(t *testing.T, bucketName string) {
|
|
// Delete all objects
|
|
resp, err := svc.ListObjects(&s3.ListObjectsInput{
|
|
Bucket: aws.String(bucketName),
|
|
})
|
|
if err != nil {
|
|
t.Logf("Failed to list objects for cleanup: %v", err)
|
|
return
|
|
}
|
|
|
|
for _, obj := range resp.Contents {
|
|
_, err := svc.DeleteObject(&s3.DeleteObjectInput{
|
|
Bucket: aws.String(bucketName),
|
|
Key: obj.Key,
|
|
})
|
|
if err != nil {
|
|
t.Logf("Failed to delete object %s: %v", *obj.Key, err)
|
|
}
|
|
}
|
|
|
|
// Give some time for eventual consistency
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
// Delete bucket
|
|
_, err = svc.DeleteBucket(&s3.DeleteBucketInput{
|
|
Bucket: aws.String(bucketName),
|
|
})
|
|
if err != nil {
|
|
t.Logf("Failed to delete bucket %s: %v", bucketName, err)
|
|
}
|
|
}
|