diff --git a/backend/internal/services/s3.go b/backend/internal/services/s3.go index 8755986..e1738b4 100644 --- a/backend/internal/services/s3.go +++ b/backend/internal/services/s3.go @@ -9,6 +9,7 @@ import ( "strings" "time" + "Noooste/garage-ui/internal/apierr" "Noooste/garage-ui/internal/config" "Noooste/garage-ui/internal/models" "Noooste/garage-ui/pkg/utils" @@ -131,7 +132,7 @@ func (s *S3Service) ListBuckets(ctx context.Context) (*models.BucketListResponse return listErr }) if err != nil { - return nil, fmt.Errorf("failed to list buckets: %w", err) + return nil, apierr.FromMinio(err) } // Convert MinIO buckets to our model @@ -164,7 +165,7 @@ func (s *S3Service) CreateBucket(ctx context.Context, bucketName string) error { }) }) if err != nil { - return fmt.Errorf("failed to create bucket %s: %w", bucketName, err) + return apierr.FromMinio(err) } return nil @@ -183,7 +184,7 @@ func (s *S3Service) DeleteBucket(ctx context.Context, bucketName string) error { return client.RemoveBucket(ctx, bucketName) }) if err != nil { - return fmt.Errorf("failed to delete bucket %s: %w", bucketName, err) + return apierr.FromMinio(err) } return nil @@ -216,7 +217,7 @@ func (s *S3Service) ListObjects(ctx context.Context, bucketName, prefix string, ) if err != nil { - return nil, fmt.Errorf("failed to list objects in bucket %s: %w", bucketName, err) + return nil, apierr.FromMinio(err) } // Drop directory marker objects (zero-byte keys ending in "/"). Garage @@ -333,7 +334,7 @@ func (s *S3Service) UploadObject(ctx context.Context, bucketName, key string, bo return uploadErr }) if err != nil { - return nil, fmt.Errorf("failed to upload object %s to bucket %s: %w", key, bucketName, err) + return nil, apierr.FromMinio(err) } return &models.ObjectUploadResponse{ @@ -366,7 +367,7 @@ func (s *S3Service) CreateDirectoryMarker(ctx context.Context, bucketName, key s return uploadErr }) if err != nil { - return nil, fmt.Errorf("failed to create directory %s in bucket %s: %w", key, bucketName, err) + return nil, apierr.FromMinio(err) } return &models.ObjectUploadResponse{ @@ -396,14 +397,14 @@ func (s *S3Service) GetObject(ctx context.Context, bucketName, key string) (io.R return getErr }) if err != nil { - return nil, nil, fmt.Errorf("failed to get object %s from bucket %s: %w", key, bucketName, err) + return nil, nil, apierr.FromMinio(err) } // Get object info stat, err := object.Stat() if err != nil { object.Close() - return nil, nil, fmt.Errorf("failed to get object info for %s in bucket %s: %w", key, bucketName, err) + return nil, nil, apierr.FromMinio(err) } // Create object info @@ -432,7 +433,7 @@ func (s *S3Service) DeleteObject(ctx context.Context, bucketName, key string) er return client.RemoveObject(ctx, bucketName, key, minio.RemoveObjectOptions{}) }) if err != nil { - return fmt.Errorf("failed to delete object %s from bucket %s: %w", key, bucketName, err) + return apierr.FromMinio(err) } return nil @@ -461,7 +462,7 @@ func (s *S3Service) ObjectExists(ctx context.Context, bucketName, key string) (b if errResponse.Code == "NoSuchKey" { return false, nil } - return false, fmt.Errorf("failed to check if object exists: %w", err) + return false, apierr.FromMinio(err) } return true, nil } @@ -484,7 +485,7 @@ func (s *S3Service) GetObjectMetadata(ctx context.Context, bucketName, key strin return statErr }) if err != nil { - return nil, fmt.Errorf("failed to get metadata for object %s in bucket %s: %w", key, bucketName, err) + return nil, apierr.FromMinio(err) } return &models.ObjectInfo{ @@ -529,7 +530,7 @@ func (s *S3Service) DeleteMultipleObjects(ctx context.Context, bucketName string // Check for errors for err := range errorCh { if err.Err != nil { - return fmt.Errorf("failed to delete object %s from bucket %s: %w", err.ObjectName, bucketName, err.Err) + return apierr.FromMinio(err.Err) } } diff --git a/backend/internal/services/s3_minio_test.go b/backend/internal/services/s3_minio_test.go index 12e7817..524e029 100644 --- a/backend/internal/services/s3_minio_test.go +++ b/backend/internal/services/s3_minio_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" "io" "net/http" @@ -13,6 +14,7 @@ import ( "testing" "time" + "Noooste/garage-ui/internal/apierr" "Noooste/garage-ui/internal/config" "Noooste/garage-ui/internal/models" "Noooste/garage-ui/pkg/utils" @@ -105,8 +107,9 @@ func TestS3_ListBuckets_ServerError(t *testing.T) { if err == nil { t.Fatal("expected error from ListBuckets, got nil") } - if !strings.Contains(err.Error(), "failed to list buckets") { - t.Errorf("error %v should wrap 'failed to list buckets'", err) + var ue *apierr.UpstreamError + if !errors.As(err, &ue) { + t.Errorf("expected *apierr.UpstreamError, got %T: %v", err, err) } } @@ -122,8 +125,9 @@ func TestS3_CreateBucket_ServerError(t *testing.T) { if err == nil { t.Fatal("expected error, got nil") } - if !strings.Contains(err.Error(), "failed to create bucket") { - t.Errorf("error = %v, want wrap 'failed to create bucket'", err) + var ue *apierr.UpstreamError + if !errors.As(err, &ue) { + t.Errorf("expected *apierr.UpstreamError, got %T: %v", err, err) } } @@ -138,8 +142,9 @@ func TestS3_DeleteBucket_ServerError(t *testing.T) { if err == nil { t.Fatal("expected error, got nil") } - if !strings.Contains(err.Error(), "failed to delete bucket") { - t.Errorf("error = %v", err) + var ue *apierr.UpstreamError + if !errors.As(err, &ue) { + t.Errorf("expected *apierr.UpstreamError, got %T: %v", err, err) } } @@ -154,8 +159,9 @@ func TestS3_ListObjects_ServerError(t *testing.T) { if err == nil { t.Fatal("expected error from ListObjects, got nil") } - if !strings.Contains(err.Error(), "failed to list objects") { - t.Errorf("error = %v", err) + var ue *apierr.UpstreamError + if !errors.As(err, &ue) { + t.Errorf("expected *apierr.UpstreamError, got %T: %v", err, err) } } @@ -170,8 +176,9 @@ func TestS3_UploadObject_ServerError(t *testing.T) { if err == nil { t.Fatal("expected error, got nil") } - if !strings.Contains(err.Error(), "failed to upload object") { - t.Errorf("error = %v", err) + var ue *apierr.UpstreamError + if !errors.As(err, &ue) { + t.Errorf("expected *apierr.UpstreamError, got %T: %v", err, err) } } @@ -186,8 +193,9 @@ func TestS3_CreateDirectoryMarker_ServerError(t *testing.T) { if err == nil { t.Fatal("expected error, got nil") } - if !strings.Contains(err.Error(), "failed to create directory") { - t.Errorf("error = %v", err) + var ue *apierr.UpstreamError + if !errors.As(err, &ue) { + t.Errorf("expected *apierr.UpstreamError, got %T: %v", err, err) } } @@ -215,8 +223,9 @@ func TestS3_DeleteObject_ServerError(t *testing.T) { if err == nil { t.Fatal("expected error, got nil") } - if !strings.Contains(err.Error(), "failed to delete object") { - t.Errorf("error = %v", err) + var ue *apierr.UpstreamError + if !errors.As(err, &ue) { + t.Errorf("expected *apierr.UpstreamError, got %T: %v", err, err) } } @@ -260,8 +269,9 @@ func TestS3_GetObjectMetadata_ServerError(t *testing.T) { if err == nil { t.Fatal("expected error, got nil") } - if !strings.Contains(err.Error(), "failed to get metadata") { - t.Errorf("error = %v", err) + var ue *apierr.UpstreamError + if !errors.As(err, &ue) { + t.Errorf("expected *apierr.UpstreamError, got %T: %v", err, err) } }