diff options
Diffstat (limited to 'test/s3/versioning/s3_bucket_creation_test.go')
| -rw-r--r-- | test/s3/versioning/s3_bucket_creation_test.go | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/test/s3/versioning/s3_bucket_creation_test.go b/test/s3/versioning/s3_bucket_creation_test.go new file mode 100644 index 000000000..36bd70ba8 --- /dev/null +++ b/test/s3/versioning/s3_bucket_creation_test.go @@ -0,0 +1,266 @@ +package s3api + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/aws/aws-sdk-go-v2/service/s3/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestBucketCreationBehavior tests the S3-compliant bucket creation behavior +func TestBucketCreationBehavior(t *testing.T) { + client := getS3Client(t) + ctx := context.Background() + + // Test cases for bucket creation behavior + testCases := []struct { + name string + setupFunc func(t *testing.T, bucketName string) // Setup before test + bucketName string + objectLockEnabled *bool + expectedStatusCode int + expectedError string + cleanupFunc func(t *testing.T, bucketName string) // Cleanup after test + }{ + { + name: "Create new bucket - should succeed", + bucketName: "test-new-bucket-" + fmt.Sprintf("%d", time.Now().Unix()), + objectLockEnabled: nil, + expectedStatusCode: 200, + expectedError: "", + }, + { + name: "Create existing bucket with same owner - should return BucketAlreadyExists", + setupFunc: func(t *testing.T, bucketName string) { + // Create bucket first + _, err := client.CreateBucket(ctx, &s3.CreateBucketInput{ + Bucket: aws.String(bucketName), + }) + require.NoError(t, err, "Setup: failed to create initial bucket") + }, + bucketName: "test-same-owner-same-settings-" + fmt.Sprintf("%d", time.Now().Unix()), + objectLockEnabled: nil, + expectedStatusCode: 409, // SeaweedFS now returns BucketAlreadyExists in all cases + expectedError: "BucketAlreadyExists", + }, + { + name: "Create bucket with same owner but different Object Lock settings - should fail", + setupFunc: func(t *testing.T, bucketName string) { + // Create bucket without Object Lock first + _, err := client.CreateBucket(ctx, &s3.CreateBucketInput{ + Bucket: aws.String(bucketName), + }) + require.NoError(t, err, "Setup: failed to create initial bucket") + }, + bucketName: "test-same-owner-diff-settings-" + fmt.Sprintf("%d", time.Now().Unix()), + objectLockEnabled: aws.Bool(true), // Try to enable Object Lock on existing bucket + expectedStatusCode: 409, + expectedError: "BucketAlreadyExists", + }, + { + name: "Create bucket with Object Lock enabled - should succeed", + bucketName: "test-object-lock-new-" + fmt.Sprintf("%d", time.Now().Unix()), + objectLockEnabled: aws.Bool(true), + expectedStatusCode: 200, + expectedError: "", + }, + { + name: "Create bucket with Object Lock enabled twice - should fail", + setupFunc: func(t *testing.T, bucketName string) { + // Create bucket with Object Lock first + _, err := client.CreateBucket(ctx, &s3.CreateBucketInput{ + Bucket: aws.String(bucketName), + ObjectLockEnabledForBucket: aws.Bool(true), + }) + require.NoError(t, err, "Setup: failed to create initial bucket with Object Lock") + }, + bucketName: "test-object-lock-duplicate-" + fmt.Sprintf("%d", time.Now().Unix()), + objectLockEnabled: aws.Bool(true), + expectedStatusCode: 409, + expectedError: "BucketAlreadyExists", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Setup + if tc.setupFunc != nil { + tc.setupFunc(t, tc.bucketName) + } + + // Cleanup function to ensure bucket is deleted after test + defer func() { + if tc.cleanupFunc != nil { + tc.cleanupFunc(t, tc.bucketName) + } else { + // Default cleanup - delete bucket and all objects + cleanupBucketForCreationTest(t, client, tc.bucketName) + } + }() + + // Execute the test - attempt to create bucket + input := &s3.CreateBucketInput{ + Bucket: aws.String(tc.bucketName), + } + if tc.objectLockEnabled != nil { + input.ObjectLockEnabledForBucket = tc.objectLockEnabled + } + + _, err := client.CreateBucket(ctx, input) + + // Verify results + if tc.expectedError == "" { + // Should succeed + assert.NoError(t, err, "Expected bucket creation to succeed") + } else { + // Should fail with specific error + assert.Error(t, err, "Expected bucket creation to fail") + if err != nil { + assert.Contains(t, err.Error(), tc.expectedError, + "Expected error to contain '%s', got: %v", tc.expectedError, err) + } + } + }) + } +} + +// TestBucketCreationWithDifferentUsers tests bucket creation with different identity contexts +func TestBucketCreationWithDifferentUsers(t *testing.T) { + // This test would require setting up different S3 credentials/identities + // For now, we'll skip this as it requires more complex setup + t.Skip("Different user testing requires IAM setup - implement when IAM is configured") + + // TODO: Implement when we have proper IAM/user management in test setup + // Should test: + // 1. User A creates bucket + // 2. User B tries to create same bucket -> should fail with BucketAlreadyExists +} + +// TestBucketCreationVersioningInteraction tests interaction between bucket creation and versioning +func TestBucketCreationVersioningInteraction(t *testing.T) { + client := getS3Client(t) + ctx := context.Background() + bucketName := "test-versioning-interaction-" + fmt.Sprintf("%d", time.Now().Unix()) + + defer cleanupBucketForCreationTest(t, client, bucketName) + + // Create bucket with Object Lock (which enables versioning) + _, err := client.CreateBucket(ctx, &s3.CreateBucketInput{ + Bucket: aws.String(bucketName), + ObjectLockEnabledForBucket: aws.Bool(true), + }) + require.NoError(t, err, "Failed to create bucket with Object Lock") + + // Verify versioning is enabled + versioningOutput, err := client.GetBucketVersioning(ctx, &s3.GetBucketVersioningInput{ + Bucket: aws.String(bucketName), + }) + require.NoError(t, err, "Failed to get bucket versioning status") + assert.Equal(t, types.BucketVersioningStatusEnabled, versioningOutput.Status, + "Expected versioning to be enabled when Object Lock is enabled") + + // Try to create the same bucket again - should fail + _, err = client.CreateBucket(ctx, &s3.CreateBucketInput{ + Bucket: aws.String(bucketName), + ObjectLockEnabledForBucket: aws.Bool(true), + }) + assert.Error(t, err, "Expected second bucket creation to fail") + assert.Contains(t, err.Error(), "BucketAlreadyExists", + "Expected BucketAlreadyExists error, got: %v", err) +} + +// TestBucketCreationErrorMessages tests that proper error messages are returned +func TestBucketCreationErrorMessages(t *testing.T) { + client := getS3Client(t) + ctx := context.Background() + bucketName := "test-error-messages-" + fmt.Sprintf("%d", time.Now().Unix()) + + defer cleanupBucketForCreationTest(t, client, bucketName) + + // Create bucket first + _, err := client.CreateBucket(ctx, &s3.CreateBucketInput{ + Bucket: aws.String(bucketName), + }) + require.NoError(t, err, "Failed to create initial bucket") + + // Try to create again and check error details + _, err = client.CreateBucket(ctx, &s3.CreateBucketInput{ + Bucket: aws.String(bucketName), + }) + + require.Error(t, err, "Expected bucket creation to fail") + + // Check that it's the right type of error + assert.Contains(t, err.Error(), "BucketAlreadyExists", + "Expected BucketAlreadyExists error, got: %v", err) +} + +// cleanupBucketForCreationTest removes a bucket and all its contents +func cleanupBucketForCreationTest(t *testing.T, client *s3.Client, bucketName string) { + ctx := context.Background() + + // List and delete all objects (including versions) + listInput := &s3.ListObjectVersionsInput{ + Bucket: aws.String(bucketName), + } + + for { + listOutput, err := client.ListObjectVersions(ctx, listInput) + if err != nil { + // Bucket might not exist, which is fine + break + } + + if len(listOutput.Versions) == 0 && len(listOutput.DeleteMarkers) == 0 { + break + } + + // Delete all versions + var objectsToDelete []types.ObjectIdentifier + for _, version := range listOutput.Versions { + objectsToDelete = append(objectsToDelete, types.ObjectIdentifier{ + Key: version.Key, + VersionId: version.VersionId, + }) + } + for _, marker := range listOutput.DeleteMarkers { + objectsToDelete = append(objectsToDelete, types.ObjectIdentifier{ + Key: marker.Key, + VersionId: marker.VersionId, + }) + } + + if len(objectsToDelete) > 0 { + _, err = client.DeleteObjects(ctx, &s3.DeleteObjectsInput{ + Bucket: aws.String(bucketName), + Delete: &types.Delete{ + Objects: objectsToDelete, + }, + }) + if err != nil { + t.Logf("Warning: failed to delete objects from bucket %s: %v", bucketName, err) + } + } + + // Check if there are more objects + if !aws.ToBool(listOutput.IsTruncated) { + break + } + listInput.KeyMarker = listOutput.NextKeyMarker + listInput.VersionIdMarker = listOutput.NextVersionIdMarker + } + + // Delete the bucket + _, err := client.DeleteBucket(ctx, &s3.DeleteBucketInput{ + Bucket: aws.String(bucketName), + }) + if err != nil { + t.Logf("Warning: failed to delete bucket %s: %v", bucketName, err) + } +} |
