package test import ( domainImage "RenewCMS/internal/domain/image" "RenewCMS/internal/infrastructure/storage" "bytes" "errors" "io" "os" "testing" ) const ( envTestS3Endpoint = "RENEWCMS_TEST_S3_ENDPOINT" envTestS3Bucket = "RENEWCMS_TEST_S3_BUCKET" envTestS3AccessKey = "RENEWCMS_TEST_S3_ACCESS_KEY" envTestS3SecretKey = "RENEWCMS_TEST_S3_SECRET_KEY" ) func TestS3StorageIntegration(t *testing.T) { endpoint := os.Getenv(envTestS3Endpoint) if endpoint == "" { t.Skipf("%s is not set, run task test:s3 to start a throwaway S3 server", envTestS3Endpoint) } store, err := storage.Open(storage.Config{Driver: storage.DriverS3, S3: storage.S3Config{ Bucket: os.Getenv(envTestS3Bucket), Region: "us-east-1", Endpoint: endpoint, AccessKeyID: os.Getenv(envTestS3AccessKey), SecretAccessKey: os.Getenv(envTestS3SecretKey), KeyPrefix: "integration/", PathStyle: true, }}) if err != nil { t.Fatalf("storage.Open failed: %v", err) } name, err := store.Put("image/png", bytes.NewReader([]byte("0123456789"))) if err != nil { t.Fatalf("Put failed: %v", err) } blob, err := store.Open(name) if err != nil { t.Fatalf("Open failed: %v", err) } if blob.Size != 10 || blob.ModTime.IsZero() { t.Errorf("unexpected blob metadata size=%d modtime=%v", blob.Size, blob.ModTime) } seeker, ok := blob.Content.(io.ReadSeeker) if !ok { t.Fatal("Content is not an io.ReadSeeker") } if _, err := seeker.Seek(4, io.SeekStart); err != nil { t.Fatalf("Seek failed: %v", err) } chunk := make([]byte, 3) if _, err := io.ReadFull(seeker, chunk); err != nil || string(chunk) != "456" { t.Errorf("ranged read = %q, %v", chunk, err) } _ = blob.Content.Close() if err := store.Delete(name); err != nil { t.Fatalf("Delete failed: %v", err) } if err := store.Delete(name); err != nil { t.Errorf("deleting a missing key must not fail, got %v", err) } if _, err := store.Open(name); !errors.Is(err, domainImage.ErrBlobNotFound) { t.Errorf("expected ErrBlobNotFound after delete, got %v", err) } }