github.com/YousefHaggyHeroku/pack@v1.5.5/internal/image/fetcher_test.go (about)

     1  package image_test
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"math/rand"
     8  	"os"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/buildpacks/imgutil/local"
    13  	"github.com/buildpacks/imgutil/remote"
    14  	"github.com/docker/docker/client"
    15  	"github.com/google/go-containerregistry/pkg/authn"
    16  	"github.com/heroku/color"
    17  	"github.com/sclevine/spec"
    18  	"github.com/sclevine/spec/report"
    19  
    20  	pubcfg "github.com/YousefHaggyHeroku/pack/config"
    21  	"github.com/YousefHaggyHeroku/pack/internal/image"
    22  	"github.com/YousefHaggyHeroku/pack/internal/logging"
    23  	h "github.com/YousefHaggyHeroku/pack/testhelpers"
    24  )
    25  
    26  var docker client.CommonAPIClient
    27  var registryConfig *h.TestRegistryConfig
    28  
    29  func TestFetcher(t *testing.T) {
    30  	rand.Seed(time.Now().UTC().UnixNano())
    31  
    32  	color.Disable(true)
    33  	defer color.Disable(false)
    34  
    35  	h.RequireDocker(t)
    36  
    37  	registryConfig = h.RunRegistry(t)
    38  	defer registryConfig.StopRegistry(t)
    39  
    40  	// TODO: is there a better solution to the auth problem?
    41  	os.Setenv("DOCKER_CONFIG", registryConfig.DockerConfigDir)
    42  
    43  	var err error
    44  	docker, err = client.NewClientWithOpts(client.FromEnv, client.WithVersion("1.38"))
    45  	h.AssertNil(t, err)
    46  	spec.Run(t, "Fetcher", testFetcher, spec.Report(report.Terminal{}))
    47  }
    48  
    49  func testFetcher(t *testing.T, when spec.G, it spec.S) {
    50  	var (
    51  		fetcher  *image.Fetcher
    52  		repoName string
    53  		repo     string
    54  		outBuf   bytes.Buffer
    55  	)
    56  
    57  	it.Before(func() {
    58  		repo = "some-org/" + h.RandString(10)
    59  		repoName = registryConfig.RepoName(repo)
    60  		fetcher = image.NewFetcher(logging.NewLogWithWriters(&outBuf, &outBuf), docker)
    61  	})
    62  
    63  	when("#Fetch", func() {
    64  		when("daemon is false", func() {
    65  			when("PullAlways", func() {
    66  				when("there is a remote image", func() {
    67  					it.Before(func() {
    68  						img, err := remote.NewImage(repoName, authn.DefaultKeychain)
    69  						h.AssertNil(t, err)
    70  
    71  						h.AssertNil(t, img.Save())
    72  					})
    73  
    74  					it("returns the remote image", func() {
    75  						_, err := fetcher.Fetch(context.TODO(), repoName, false, pubcfg.PullAlways)
    76  						h.AssertNil(t, err)
    77  					})
    78  				})
    79  
    80  				when("there is no remote image", func() {
    81  					it("returns an error", func() {
    82  						_, err := fetcher.Fetch(context.TODO(), repoName, false, pubcfg.PullAlways)
    83  						h.AssertError(t, err, fmt.Sprintf("image '%s' does not exist in registry", repoName))
    84  					})
    85  				})
    86  			})
    87  
    88  			when("PullIfNotPresent", func() {
    89  				when("there is a remote image", func() {
    90  					it.Before(func() {
    91  						img, err := remote.NewImage(repoName, authn.DefaultKeychain)
    92  						h.AssertNil(t, err)
    93  
    94  						h.AssertNil(t, img.Save())
    95  					})
    96  
    97  					it("returns the remote image", func() {
    98  						_, err := fetcher.Fetch(context.TODO(), repoName, false, pubcfg.PullIfNotPresent)
    99  						h.AssertNil(t, err)
   100  					})
   101  				})
   102  
   103  				when("there is no remote image", func() {
   104  					it("returns an error", func() {
   105  						_, err := fetcher.Fetch(context.TODO(), repoName, false, pubcfg.PullIfNotPresent)
   106  						h.AssertError(t, err, fmt.Sprintf("image '%s' does not exist in registry", repoName))
   107  					})
   108  				})
   109  			})
   110  		})
   111  
   112  		when("daemon is true", func() {
   113  			when("PullNever", func() {
   114  				when("there is a local image", func() {
   115  					it.Before(func() {
   116  						// Make sure the repoName is not a valid remote repo.
   117  						// This is to verify that no remote check is made
   118  						// when there's a valid local image.
   119  						repoName = "invalidhost" + repoName
   120  
   121  						img, err := local.NewImage(repoName, docker)
   122  						h.AssertNil(t, err)
   123  
   124  						h.AssertNil(t, img.Save())
   125  					})
   126  
   127  					it.After(func() {
   128  						h.DockerRmi(docker, repoName)
   129  					})
   130  
   131  					it("returns the local image", func() {
   132  						_, err := fetcher.Fetch(context.TODO(), repoName, true, pubcfg.PullNever)
   133  						h.AssertNil(t, err)
   134  					})
   135  				})
   136  
   137  				when("there is no local image", func() {
   138  					it("returns an error", func() {
   139  						_, err := fetcher.Fetch(context.TODO(), repoName, true, pubcfg.PullNever)
   140  						h.AssertError(t, err, fmt.Sprintf("image '%s' does not exist on the daemon", repoName))
   141  					})
   142  				})
   143  			})
   144  
   145  			when("PullAlways", func() {
   146  				when("there is a remote image", func() {
   147  					var (
   148  						logger *logging.LogWithWriters
   149  						output func() string
   150  					)
   151  
   152  					it.Before(func() {
   153  						// Instantiate a pull-able local image
   154  						// as opposed to a remote image so that the image
   155  						// is created with the OS of the docker daemon
   156  						img, err := local.NewImage(repoName, docker)
   157  						h.AssertNil(t, err)
   158  						defer h.DockerRmi(docker, repoName)
   159  
   160  						h.AssertNil(t, img.Save())
   161  
   162  						h.AssertNil(t, h.PushImage(docker, img.Name(), registryConfig))
   163  
   164  						var outCons *color.Console
   165  						outCons, output = h.MockWriterAndOutput()
   166  						logger = logging.NewLogWithWriters(outCons, outCons)
   167  						fetcher = image.NewFetcher(logger, docker)
   168  					})
   169  
   170  					it.After(func() {
   171  						h.DockerRmi(docker, repoName)
   172  					})
   173  
   174  					it("pull the image and return the local copy", func() {
   175  						_, err := fetcher.Fetch(context.TODO(), repoName, true, pubcfg.PullAlways)
   176  						h.AssertNil(t, err)
   177  						h.AssertNotEq(t, output(), "")
   178  					})
   179  
   180  					it("doesn't log anything in quiet mode", func() {
   181  						logger.WantQuiet(true)
   182  						_, err := fetcher.Fetch(context.TODO(), repoName, true, pubcfg.PullAlways)
   183  						h.AssertNil(t, err)
   184  						h.AssertEq(t, output(), "")
   185  					})
   186  				})
   187  
   188  				when("there is no remote image", func() {
   189  					when("there is a local image", func() {
   190  						it.Before(func() {
   191  							img, err := local.NewImage(repoName, docker)
   192  							h.AssertNil(t, err)
   193  
   194  							h.AssertNil(t, img.Save())
   195  						})
   196  
   197  						it.After(func() {
   198  							h.DockerRmi(docker, repoName)
   199  						})
   200  
   201  						it("returns the local image", func() {
   202  							_, err := fetcher.Fetch(context.TODO(), repoName, true, pubcfg.PullAlways)
   203  							h.AssertNil(t, err)
   204  						})
   205  					})
   206  
   207  					when("there is no local image", func() {
   208  						it("returns an error", func() {
   209  							_, err := fetcher.Fetch(context.TODO(), repoName, true, pubcfg.PullAlways)
   210  							h.AssertError(t, err, fmt.Sprintf("image '%s' does not exist on the daemon", repoName))
   211  						})
   212  					})
   213  				})
   214  			})
   215  
   216  			when("PullIfNotPresent", func() {
   217  				when("there is a remote image", func() {
   218  					var (
   219  						label          = "label"
   220  						remoteImgLabel string
   221  					)
   222  
   223  					it.Before(func() {
   224  						// Instantiate a pull-able local image
   225  						// as opposed to a remote image so that the image
   226  						// is created with the OS of the docker daemon
   227  						remoteImg, err := local.NewImage(repoName, docker)
   228  						h.AssertNil(t, err)
   229  						defer h.DockerRmi(docker, repoName)
   230  
   231  						h.AssertNil(t, remoteImg.SetLabel(label, "1"))
   232  						h.AssertNil(t, remoteImg.Save())
   233  
   234  						h.AssertNil(t, h.PushImage(docker, remoteImg.Name(), registryConfig))
   235  
   236  						remoteImgLabel, err = remoteImg.Label(label)
   237  						h.AssertNil(t, err)
   238  					})
   239  
   240  					it.After(func() {
   241  						h.DockerRmi(docker, repoName)
   242  					})
   243  
   244  					when("there is a local image", func() {
   245  						var localImgLabel string
   246  
   247  						it.Before(func() {
   248  							localImg, err := local.NewImage(repoName, docker)
   249  							h.AssertNil(t, localImg.SetLabel(label, "2"))
   250  							h.AssertNil(t, err)
   251  
   252  							h.AssertNil(t, localImg.Save())
   253  
   254  							localImgLabel, err = localImg.Label(label)
   255  							h.AssertNil(t, err)
   256  						})
   257  
   258  						it.After(func() {
   259  							h.DockerRmi(docker, repoName)
   260  						})
   261  
   262  						it("returns the local image", func() {
   263  							fetchedImg, err := fetcher.Fetch(context.TODO(), repoName, true, pubcfg.PullIfNotPresent)
   264  							h.AssertNil(t, err)
   265  							h.AssertNotContains(t, outBuf.String(), "Pulling image")
   266  
   267  							fetchedImgLabel, err := fetchedImg.Label(label)
   268  							h.AssertNil(t, err)
   269  
   270  							h.AssertEq(t, fetchedImgLabel, localImgLabel)
   271  							h.AssertNotEq(t, fetchedImgLabel, remoteImgLabel)
   272  						})
   273  					})
   274  
   275  					when("there is no local image", func() {
   276  						it("returns the remote image", func() {
   277  							fetchedImg, err := fetcher.Fetch(context.TODO(), repoName, true, pubcfg.PullIfNotPresent)
   278  							h.AssertNil(t, err)
   279  
   280  							fetchedImgLabel, err := fetchedImg.Label(label)
   281  							h.AssertNil(t, err)
   282  							h.AssertEq(t, fetchedImgLabel, remoteImgLabel)
   283  						})
   284  					})
   285  				})
   286  
   287  				when("there is no remote image", func() {
   288  					when("there is a local image", func() {
   289  						it.Before(func() {
   290  							img, err := local.NewImage(repoName, docker)
   291  							h.AssertNil(t, err)
   292  
   293  							h.AssertNil(t, img.Save())
   294  						})
   295  
   296  						it.After(func() {
   297  							h.DockerRmi(docker, repoName)
   298  						})
   299  
   300  						it("returns the local image", func() {
   301  							_, err := fetcher.Fetch(context.TODO(), repoName, true, pubcfg.PullIfNotPresent)
   302  							h.AssertNil(t, err)
   303  						})
   304  					})
   305  
   306  					when("there is no local image", func() {
   307  						it("returns an error", func() {
   308  							_, err := fetcher.Fetch(context.TODO(), repoName, true, pubcfg.PullIfNotPresent)
   309  							h.AssertError(t, err, fmt.Sprintf("image '%s' does not exist on the daemon", repoName))
   310  						})
   311  					})
   312  				})
   313  			})
   314  		})
   315  	})
   316  }