| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- 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)
- }
- }
|