aboutsummaryrefslogtreecommitdiff
path: root/test/s3/basic/delimiter_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'test/s3/basic/delimiter_test.go')
-rw-r--r--test/s3/basic/delimiter_test.go169
1 files changed, 169 insertions, 0 deletions
diff --git a/test/s3/basic/delimiter_test.go b/test/s3/basic/delimiter_test.go
new file mode 100644
index 000000000..a501f83b6
--- /dev/null
+++ b/test/s3/basic/delimiter_test.go
@@ -0,0 +1,169 @@
+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)
+ }
+}