-
Notifications
You must be signed in to change notification settings - Fork 135
feat(minio): ensure bucket exists on storage init #43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,56 @@ | ||||||
| //go:build integration | ||||||
|
|
||||||
| package minio_storage | ||||||
|
|
||||||
| import ( | ||||||
| "os" | ||||||
| "strconv" | ||||||
| "testing" | ||||||
| ) | ||||||
|
|
||||||
| // TestNewMinioMediaStorage_CreatesBucket runs against a real MinIO/S3-compatible endpoint. | ||||||
| // Example: | ||||||
| // | ||||||
| // MINIO_INTEGRATION_TEST=1 \ | ||||||
| // MINIO_ENDPOINT=localhost:9000 \ | ||||||
| // MINIO_ACCESS_KEY=minioadmin \ | ||||||
| // MINIO_SECRET_KEY=minioadmin \ | ||||||
| // MINIO_BUCKET=evolution-test-bucket \ | ||||||
| // MINIO_REGION=us-east-1 \ | ||||||
| // MINIO_USE_SSL=false \ | ||||||
| // go test -tags=integration ./pkg/storage/minio/... | ||||||
| func TestNewMinioMediaStorage_CreatesBucket(t *testing.T) { | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion (testing): Integration test name suggests bucket creation but the test only asserts successful initialization Right now it only verifies that
Suggested change
|
||||||
| if os.Getenv("MINIO_INTEGRATION_TEST") == "" { | ||||||
| t.Skip("set MINIO_INTEGRATION_TEST=1 and MinIO env vars to run") | ||||||
| } | ||||||
|
|
||||||
| endpoint := os.Getenv("MINIO_ENDPOINT") | ||||||
| access := os.Getenv("MINIO_ACCESS_KEY") | ||||||
| secret := os.Getenv("MINIO_SECRET_KEY") | ||||||
| bucket := os.Getenv("MINIO_BUCKET") | ||||||
| region := os.Getenv("MINIO_REGION") | ||||||
| if region == "" { | ||||||
| region = "us-east-1" | ||||||
| } | ||||||
|
|
||||||
| useSSL := false | ||||||
| if v := os.Getenv("MINIO_USE_SSL"); v != "" { | ||||||
| var err error | ||||||
| useSSL, err = strconv.ParseBool(v) | ||||||
| if err != nil { | ||||||
| t.Fatalf("MINIO_USE_SSL: %v", err) | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| if endpoint == "" || access == "" || secret == "" || bucket == "" { | ||||||
| t.Fatal("MINIO_ENDPOINT, MINIO_ACCESS_KEY, MINIO_SECRET_KEY, MINIO_BUCKET are required") | ||||||
| } | ||||||
|
|
||||||
| st, err := NewMinioMediaStorage(endpoint, access, secret, bucket, region, useSSL) | ||||||
| if err != nil { | ||||||
| t.Fatalf("NewMinioMediaStorage: %v", err) | ||||||
| } | ||||||
| if st == nil { | ||||||
| t.Fatal("expected non-nil storage") | ||||||
| } | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| package minio_storage | ||
|
|
||
| import ( | ||
| "context" | ||
| "errors" | ||
| "testing" | ||
|
|
||
| "github.com/minio/minio-go/v7" | ||
| ) | ||
|
|
||
| type fakeMinioBucket struct { | ||
| exists bool | ||
| existsErr error | ||
| makeErr error | ||
| makeCalls int | ||
| lastBucket string | ||
| lastRegion string | ||
| existsCalls int | ||
| } | ||
|
|
||
| func (f *fakeMinioBucket) BucketExists(ctx context.Context, bucketName string) (bool, error) { | ||
| _ = ctx | ||
| f.existsCalls++ | ||
| f.lastBucket = bucketName | ||
| return f.exists, f.existsErr | ||
| } | ||
|
|
||
| func (f *fakeMinioBucket) MakeBucket(ctx context.Context, bucketName string, opts minio.MakeBucketOptions) error { | ||
| _ = ctx | ||
| f.makeCalls++ | ||
| f.lastBucket = bucketName | ||
| f.lastRegion = opts.Region | ||
| return f.makeErr | ||
| } | ||
|
|
||
| func TestEnsureBucketExists_AlreadyThere(t *testing.T) { | ||
| f := &fakeMinioBucket{exists: true} | ||
| err := ensureBucketExists(context.Background(), f, "my-bucket", "us-east-1") | ||
| if err != nil { | ||
| t.Fatalf("unexpected error: %v", err) | ||
| } | ||
| if f.makeCalls != 0 { | ||
| t.Fatalf("MakeBucket should not run when bucket exists, calls=%d", f.makeCalls) | ||
| } | ||
| if f.existsCalls != 1 { | ||
| t.Fatalf("expected 1 BucketExists call, got %d", f.existsCalls) | ||
| } | ||
| } | ||
|
|
||
| func TestEnsureBucketExists_CreatesWhenMissing(t *testing.T) { | ||
| f := &fakeMinioBucket{exists: false} | ||
| err := ensureBucketExists(context.Background(), f, "new-bucket", "eu-west-1") | ||
| if err != nil { | ||
| t.Fatalf("unexpected error: %v", err) | ||
| } | ||
| if f.makeCalls != 1 { | ||
| t.Fatalf("expected 1 MakeBucket call, got %d", f.makeCalls) | ||
| } | ||
| if f.lastBucket != "new-bucket" || f.lastRegion != "eu-west-1" { | ||
| t.Fatalf("unexpected MakeBucket args: bucket=%q region=%q", f.lastBucket, f.lastRegion) | ||
| } | ||
| } | ||
|
|
||
| func TestEnsureBucketExists_BucketExistsError(t *testing.T) { | ||
| f := &fakeMinioBucket{existsErr: errors.New("network down")} | ||
| err := ensureBucketExists(context.Background(), f, "b", "r") | ||
| if err == nil { | ||
| t.Fatal("expected error") | ||
| } | ||
| } | ||
|
|
||
| func TestEnsureBucketExists_MakeBucketError(t *testing.T) { | ||
| f := &fakeMinioBucket{exists: false, makeErr: errors.New("access denied")} | ||
| err := ensureBucketExists(context.Background(), f, "b", "r") | ||
| if err == nil { | ||
| t.Fatal("expected error") | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: Avoid direct fmt.Printf in library code and rely on a logger or remove non-essential logging.
Writing to stdout from this helper can be unexpected for callers and noisy in production. Please either remove this success log or send it through the service’s logger so callers can control log levels and outputs.