github.com/buildpacks/pack@v0.33.3-0.20240516162812-884dd1837311/pkg/blob/downloader_test.go (about)

     1  package blob_test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"net/http"
     8  	"os"
     9  	"path/filepath"
    10  	"testing"
    11  
    12  	"github.com/heroku/color"
    13  	"github.com/onsi/gomega/ghttp"
    14  	"github.com/sclevine/spec"
    15  	"github.com/sclevine/spec/report"
    16  
    17  	"github.com/buildpacks/pack/internal/paths"
    18  	"github.com/buildpacks/pack/pkg/archive"
    19  	"github.com/buildpacks/pack/pkg/blob"
    20  	h "github.com/buildpacks/pack/testhelpers"
    21  )
    22  
    23  func TestDownloader(t *testing.T) {
    24  	color.Disable(true)
    25  	defer color.Disable(false)
    26  	spec.Run(t, "Downloader", testDownloader, spec.Sequential(), spec.Report(report.Terminal{}))
    27  }
    28  
    29  func testDownloader(t *testing.T, when spec.G, it spec.S) {
    30  	when("#Download", func() {
    31  		var (
    32  			cacheDir string
    33  			err      error
    34  			subject  blob.Downloader
    35  		)
    36  
    37  		it.Before(func() {
    38  			cacheDir, err = os.MkdirTemp("", "cache")
    39  			h.AssertNil(t, err)
    40  			subject = blob.NewDownloader(&logger{io.Discard}, cacheDir)
    41  		})
    42  
    43  		it.After(func() {
    44  			h.AssertNil(t, os.RemoveAll(cacheDir))
    45  		})
    46  
    47  		when("is path", func() {
    48  			var (
    49  				relPath string
    50  			)
    51  
    52  			it.Before(func() {
    53  				relPath = filepath.Join("testdata", "blob")
    54  			})
    55  
    56  			when("is absolute", func() {
    57  				it("return the absolute path", func() {
    58  					absPath, err := filepath.Abs(relPath)
    59  					h.AssertNil(t, err)
    60  
    61  					b, err := subject.Download(context.TODO(), absPath)
    62  					h.AssertNil(t, err)
    63  					assertBlob(t, b)
    64  				})
    65  			})
    66  
    67  			when("is relative", func() {
    68  				it("resolves the absolute path", func() {
    69  					b, err := subject.Download(context.TODO(), relPath)
    70  					h.AssertNil(t, err)
    71  					assertBlob(t, b)
    72  				})
    73  			})
    74  
    75  			when("path is a file:// uri", func() {
    76  				it("resolves the absolute path", func() {
    77  					absPath, err := filepath.Abs(relPath)
    78  					h.AssertNil(t, err)
    79  
    80  					uri, err := paths.FilePathToURI(absPath, "")
    81  					h.AssertNil(t, err)
    82  
    83  					b, err := subject.Download(context.TODO(), uri)
    84  					h.AssertNil(t, err)
    85  					assertBlob(t, b)
    86  				})
    87  			})
    88  		})
    89  
    90  		when("is uri", func() {
    91  			var (
    92  				server *ghttp.Server
    93  				uri    string
    94  				tgz    string
    95  			)
    96  
    97  			it.Before(func() {
    98  				server = ghttp.NewServer()
    99  				uri = server.URL() + "/downloader/somefile.tgz"
   100  
   101  				tgz = h.CreateTGZ(t, filepath.Join("testdata", "blob"), "./", 0777)
   102  			})
   103  
   104  			it.After(func() {
   105  				os.Remove(tgz)
   106  				server.Close()
   107  			})
   108  
   109  			when("uri is valid", func() {
   110  				it.Before(func() {
   111  					server.AppendHandlers(func(w http.ResponseWriter, r *http.Request) {
   112  						w.Header().Add("ETag", "A")
   113  						http.ServeFile(w, r, tgz)
   114  					})
   115  
   116  					server.AppendHandlers(func(w http.ResponseWriter, r *http.Request) {
   117  						w.WriteHeader(304)
   118  					})
   119  				})
   120  
   121  				it("downloads from a 'http(s)://' URI", func() {
   122  					b, err := subject.Download(context.TODO(), uri)
   123  					h.AssertNil(t, err)
   124  					assertBlob(t, b)
   125  				})
   126  
   127  				it("uses cache from a 'http(s)://' URI tgz", func() {
   128  					b, err := subject.Download(context.TODO(), uri)
   129  					h.AssertNil(t, err)
   130  					assertBlob(t, b)
   131  
   132  					b, err = subject.Download(context.TODO(), uri)
   133  					h.AssertNil(t, err)
   134  					assertBlob(t, b)
   135  				})
   136  			})
   137  
   138  			when("uri is invalid", func() {
   139  				when("uri file is not found", func() {
   140  					it.Before(func() {
   141  						server.AppendHandlers(func(w http.ResponseWriter, r *http.Request) {
   142  							w.WriteHeader(404)
   143  						})
   144  
   145  						server.AppendHandlers(func(w http.ResponseWriter, r *http.Request) {
   146  							w.WriteHeader(404)
   147  						})
   148  					})
   149  
   150  					it("should return error", func() {
   151  						_, err := subject.Download(context.TODO(), uri)
   152  						h.AssertError(t, err, "could not download")
   153  						h.AssertError(t, err, "http status '404'")
   154  					})
   155  				})
   156  
   157  				when("uri is unsupported", func() {
   158  					it("should return error", func() {
   159  						_, err := subject.Download(context.TODO(), "not-supported://file.tgz")
   160  						h.AssertError(t, err, "unsupported protocol 'not-supported'")
   161  					})
   162  				})
   163  			})
   164  		})
   165  	})
   166  }
   167  
   168  func assertBlob(t *testing.T, b blob.Blob) {
   169  	t.Helper()
   170  	r, err := b.Open()
   171  	h.AssertNil(t, err)
   172  	defer r.Close()
   173  
   174  	_, bytes, err := archive.ReadTarEntry(r, "file.txt")
   175  	h.AssertNil(t, err)
   176  
   177  	h.AssertEq(t, string(bytes), "contents")
   178  }
   179  
   180  type logger struct {
   181  	writer io.Writer
   182  }
   183  
   184  func (l *logger) Debugf(format string, v ...interface{}) {
   185  	fmt.Fprintln(l.writer, format, v)
   186  }
   187  
   188  func (l *logger) Infof(format string, v ...interface{}) {
   189  	fmt.Fprintln(l.writer, format, v)
   190  }
   191  
   192  func (l *logger) Writer() io.Writer {
   193  	return l.writer
   194  }