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