Adds bucket management capabilities: - ListBuckets: list all buckets for AWS account with owner info - CreateBucket: create bucket with optional region support - DeleteBucket: delete empty buckets Includes comprehensive tests and README documentation. Prompt: "Please review the changes we have made for this bucket api"
255 lines
5.8 KiB
Go
255 lines
5.8 KiB
Go
package simples3
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func setupTestS3(t *testing.T) *S3 {
|
|
t.Helper()
|
|
|
|
s3 := New(
|
|
os.Getenv("AWS_S3_REGION"),
|
|
os.Getenv("AWS_S3_ACCESS_KEY"),
|
|
os.Getenv("AWS_S3_SECRET_KEY"),
|
|
)
|
|
|
|
if endpoint := os.Getenv("AWS_S3_ENDPOINT"); endpoint != "" {
|
|
s3.SetEndpoint(endpoint)
|
|
}
|
|
|
|
return s3
|
|
}
|
|
|
|
func TestListBuckets(t *testing.T) {
|
|
s3 := setupTestS3(t)
|
|
|
|
result, err := s3.ListBuckets(ListBucketsInput{})
|
|
if err != nil {
|
|
t.Fatalf("ListBuckets failed: %v", err)
|
|
}
|
|
|
|
// ListBuckets should succeed even if there are no buckets
|
|
t.Logf("Found %d bucket(s)", len(result.Buckets))
|
|
for _, bucket := range result.Buckets {
|
|
t.Logf(" - %s (created: %s)", bucket.Name, bucket.CreationDate)
|
|
}
|
|
|
|
// Verify Owner information is present
|
|
if result.Owner.ID != "" {
|
|
t.Logf("Owner ID: %s", result.Owner.ID)
|
|
}
|
|
if result.Owner.DisplayName != "" {
|
|
t.Logf("Owner DisplayName: %s", result.Owner.DisplayName)
|
|
}
|
|
}
|
|
|
|
func TestCreateAndDeleteBucket(t *testing.T) {
|
|
s3 := setupTestS3(t)
|
|
|
|
// Generate a unique bucket name using timestamp
|
|
testBucket := fmt.Sprintf("simples3-test-%d", time.Now().Unix())
|
|
|
|
t.Run("CreateBucket", func(t *testing.T) {
|
|
output, err := s3.CreateBucket(CreateBucketInput{
|
|
Bucket: testBucket,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("CreateBucket failed: %v", err)
|
|
}
|
|
t.Logf("Created bucket: %s", testBucket)
|
|
if output.Location != "" {
|
|
t.Logf("Location: %s", output.Location)
|
|
}
|
|
})
|
|
|
|
// Give S3/MinIO a moment to propagate the bucket creation
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
t.Run("VerifyBucketExists", func(t *testing.T) {
|
|
result, err := s3.ListBuckets(ListBucketsInput{})
|
|
if err != nil {
|
|
t.Fatalf("ListBuckets failed: %v", err)
|
|
}
|
|
|
|
found := false
|
|
for _, bucket := range result.Buckets {
|
|
if bucket.Name == testBucket {
|
|
found = true
|
|
t.Logf("Verified bucket exists: %s (created: %s)", bucket.Name, bucket.CreationDate)
|
|
break
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
t.Errorf("Created bucket %s not found in ListBuckets", testBucket)
|
|
}
|
|
})
|
|
|
|
t.Run("DeleteBucket", func(t *testing.T) {
|
|
err := s3.DeleteBucket(DeleteBucketInput{
|
|
Bucket: testBucket,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("DeleteBucket failed: %v", err)
|
|
}
|
|
t.Logf("Deleted bucket: %s", testBucket)
|
|
})
|
|
|
|
// Give S3/MinIO a moment to propagate the bucket deletion
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
t.Run("VerifyBucketDeleted", func(t *testing.T) {
|
|
result, err := s3.ListBuckets(ListBucketsInput{})
|
|
if err != nil {
|
|
t.Fatalf("ListBuckets failed: %v", err)
|
|
}
|
|
|
|
found := false
|
|
for _, bucket := range result.Buckets {
|
|
if bucket.Name == testBucket {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if found {
|
|
t.Errorf("Deleted bucket %s still appears in ListBuckets", testBucket)
|
|
} else {
|
|
t.Logf("Verified bucket deleted: %s", testBucket)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCreateBucket_WithRegion(t *testing.T) {
|
|
s3 := setupTestS3(t)
|
|
|
|
// Generate a unique bucket name
|
|
testBucket := fmt.Sprintf("simples3-test-region-%d", time.Now().Unix())
|
|
|
|
// Create bucket with explicit region
|
|
region := os.Getenv("AWS_S3_REGION")
|
|
if region == "" {
|
|
region = "us-east-1"
|
|
}
|
|
|
|
output, err := s3.CreateBucket(CreateBucketInput{
|
|
Bucket: testBucket,
|
|
Region: region,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("CreateBucket with region failed: %v", err)
|
|
}
|
|
t.Logf("Created bucket with region %s: %s", region, testBucket)
|
|
if output.Location != "" {
|
|
t.Logf("Location: %s", output.Location)
|
|
}
|
|
|
|
// Cleanup
|
|
defer func() {
|
|
time.Sleep(100 * time.Millisecond)
|
|
err := s3.DeleteBucket(DeleteBucketInput{
|
|
Bucket: testBucket,
|
|
})
|
|
if err != nil {
|
|
t.Logf("Failed to cleanup bucket %s: %v", testBucket, err)
|
|
}
|
|
}()
|
|
|
|
// Verify bucket exists
|
|
result, err := s3.ListBuckets(ListBucketsInput{})
|
|
if err != nil {
|
|
t.Fatalf("ListBuckets failed: %v", err)
|
|
}
|
|
|
|
found := false
|
|
for _, bucket := range result.Buckets {
|
|
if bucket.Name == testBucket {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
t.Errorf("Created bucket %s not found in ListBuckets", testBucket)
|
|
}
|
|
}
|
|
|
|
func TestCreateBucket_EmptyName(t *testing.T) {
|
|
s3 := setupTestS3(t)
|
|
|
|
_, err := s3.CreateBucket(CreateBucketInput{
|
|
Bucket: "",
|
|
})
|
|
if err == nil {
|
|
t.Error("Expected error when creating bucket with empty name, got nil")
|
|
}
|
|
if err != nil && err.Error() != "bucket name is required" {
|
|
t.Errorf("Expected 'bucket name is required' error, got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestDeleteBucket_EmptyName(t *testing.T) {
|
|
s3 := setupTestS3(t)
|
|
|
|
err := s3.DeleteBucket(DeleteBucketInput{
|
|
Bucket: "",
|
|
})
|
|
if err == nil {
|
|
t.Error("Expected error when deleting bucket with empty name, got nil")
|
|
}
|
|
if err != nil && err.Error() != "bucket name is required" {
|
|
t.Errorf("Expected 'bucket name is required' error, got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestDeleteBucket_NonExistent(t *testing.T) {
|
|
s3 := setupTestS3(t)
|
|
|
|
// Try to delete a bucket that doesn't exist
|
|
nonExistentBucket := fmt.Sprintf("nonexistent-bucket-%d", time.Now().Unix())
|
|
err := s3.DeleteBucket(DeleteBucketInput{
|
|
Bucket: nonExistentBucket,
|
|
})
|
|
if err == nil {
|
|
t.Error("Expected error when deleting non-existent bucket, got nil")
|
|
} else {
|
|
t.Logf("Got expected error for non-existent bucket: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCreateBucket_Duplicate(t *testing.T) {
|
|
s3 := setupTestS3(t)
|
|
|
|
testBucket := fmt.Sprintf("simples3-test-dup-%d", time.Now().Unix())
|
|
|
|
// Create bucket first time
|
|
_, err := s3.CreateBucket(CreateBucketInput{
|
|
Bucket: testBucket,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("First CreateBucket failed: %v", err)
|
|
}
|
|
|
|
defer func() {
|
|
time.Sleep(100 * time.Millisecond)
|
|
s3.DeleteBucket(DeleteBucketInput{
|
|
Bucket: testBucket,
|
|
})
|
|
}()
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
// Try to create the same bucket again
|
|
_, err = s3.CreateBucket(CreateBucketInput{
|
|
Bucket: testBucket,
|
|
})
|
|
if err == nil {
|
|
t.Error("Expected error when creating duplicate bucket, got nil")
|
|
} else {
|
|
t.Logf("Got expected error for duplicate bucket: %v", err)
|
|
}
|
|
}
|