github.com/jenspinney/cli@v6.42.1-0.20190207184520-7450c600020e+incompatible/actor/v7action/buildpack_test.go (about)

     1  package v7action_test
     2  
     3  import (
     4  	"code.cloudfoundry.org/cli/actor/actionerror"
     5  	. "code.cloudfoundry.org/cli/actor/v7action"
     6  	"code.cloudfoundry.org/cli/actor/v7action/v7actionfakes"
     7  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
     8  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3"
     9  	"code.cloudfoundry.org/cli/types"
    10  	"errors"
    11  	. "github.com/onsi/ginkgo"
    12  	. "github.com/onsi/gomega"
    13  	"io"
    14  	"io/ioutil"
    15  	"os"
    16  	"path/filepath"
    17  	"strings"
    18  )
    19  
    20  var _ = Describe("Buildpack", func() {
    21  	var (
    22  		actor                     *Actor
    23  		fakeCloudControllerClient *v7actionfakes.FakeCloudControllerClient
    24  	)
    25  
    26  	BeforeEach(func() {
    27  		actor, fakeCloudControllerClient, _, _, _ = NewTestActor()
    28  	})
    29  
    30  	Describe("GetBuildpackByNameAndStack", func() {
    31  		var (
    32  			buildpackName  = "buildpack-1"
    33  			buildpackStack = "stack-name"
    34  			buildpack      Buildpack
    35  			warnings       Warnings
    36  			executeErr     error
    37  		)
    38  
    39  		JustBeforeEach(func() {
    40  			buildpack, warnings, executeErr = actor.GetBuildpackByNameAndStack(buildpackName, buildpackStack)
    41  		})
    42  
    43  		When("getting buildpacks fails", func() {
    44  			BeforeEach(func() {
    45  
    46  				buildpackStack = "real-good-stack"
    47  				fakeCloudControllerClient.GetBuildpacksReturns(
    48  					nil,
    49  					ccv3.Warnings{"some-warning-1", "some-warning-2"},
    50  					errors.New("some-error"))
    51  			})
    52  
    53  			It("returns warnings and error", func() {
    54  				Expect(executeErr).To(MatchError("some-error"))
    55  				Expect(warnings).To(ConsistOf("some-warning-1", "some-warning-2"))
    56  				Expect(fakeCloudControllerClient.GetBuildpacksCallCount()).To(Equal(1))
    57  				queries := fakeCloudControllerClient.GetBuildpacksArgsForCall(0)
    58  				Expect(queries).To(ConsistOf(
    59  					ccv3.Query{
    60  						Key:    ccv3.NameFilter,
    61  						Values: []string{buildpackName},
    62  					},
    63  					ccv3.Query{
    64  						Key:    ccv3.StackFilter,
    65  						Values: []string{buildpackStack},
    66  					},
    67  				))
    68  			})
    69  		})
    70  
    71  		When("multiple buildpacks with stacks are returned", func() {
    72  			BeforeEach(func() {
    73  				ccBuildpacks := []ccv3.Buildpack{
    74  					{Name: buildpackName, Stack: "a-real-stack", Position: types.NullInt{Value: 1, IsSet: true}},
    75  					{Name: buildpackName, Stack: "another-stack", Position: types.NullInt{Value: 2, IsSet: true}},
    76  				}
    77  
    78  				fakeCloudControllerClient.GetBuildpacksReturns(
    79  					ccBuildpacks,
    80  					ccv3.Warnings{"some-warning-1", "some-warning-2"},
    81  					nil)
    82  			})
    83  
    84  			It("returns warnings and MultipleBuildpacksFoundError", func() {
    85  				Expect(executeErr).To(MatchError(actionerror.MultipleBuildpacksFoundError{BuildpackName: buildpackName}))
    86  				Expect(warnings).To(ConsistOf("some-warning-1", "some-warning-2"))
    87  			})
    88  
    89  		})
    90  
    91  		When("multiple buildpacks including one with no stack are returned", func() {
    92  			BeforeEach(func() {
    93  				ccBuildpacks := []ccv3.Buildpack{
    94  					{GUID: "buildpack-1-guid", Name: "buildpack-1", Stack: "a-real-stack", Position: types.NullInt{Value: 1, IsSet: true}},
    95  					{GUID: "buildpack-2-guid", Name: "buildpack-2", Stack: "", Position: types.NullInt{Value: 2, IsSet: true}},
    96  				}
    97  
    98  				fakeCloudControllerClient.GetBuildpacksReturns(
    99  					ccBuildpacks,
   100  					ccv3.Warnings{"some-warning-1", "some-warning-2"},
   101  					nil)
   102  			})
   103  
   104  			It("returns the nil stack buildpack and any warnings", func() {
   105  				Expect(executeErr).ToNot(HaveOccurred())
   106  				Expect(buildpack).To(Equal(Buildpack{Name: "buildpack-2", GUID: "buildpack-2-guid", Stack: "", Position: types.NullInt{Value: 2, IsSet: true}}))
   107  				Expect(warnings).To(ConsistOf("some-warning-1", "some-warning-2"))
   108  			})
   109  		})
   110  
   111  		When("zero buildpacks are returned", func() {
   112  			BeforeEach(func() {
   113  				var ccBuildpacks []ccv3.Buildpack
   114  
   115  				fakeCloudControllerClient.GetBuildpacksReturns(
   116  					ccBuildpacks,
   117  					ccv3.Warnings{"some-warning-1", "some-warning-2"},
   118  					nil)
   119  			})
   120  
   121  			It("returns warnings and a BuilpackNotFoundError", func() {
   122  				Expect(executeErr).To(MatchError(actionerror.BuildpackNotFoundError{BuildpackName: buildpackName, StackName: buildpackStack}))
   123  				Expect(warnings).To(ConsistOf("some-warning-1", "some-warning-2"))
   124  			})
   125  		})
   126  
   127  		When("getting buildpacks is successful", func() {
   128  			When("No stack is specified", func() {
   129  				BeforeEach(func() {
   130  					buildpackStack = ""
   131  					buildpackName = "my-buildpack"
   132  
   133  					ccBuildpack := ccv3.Buildpack{Name: "my-buildpack", GUID: "some-guid"}
   134  					fakeCloudControllerClient.GetBuildpacksReturns(
   135  						[]ccv3.Buildpack{ccBuildpack},
   136  						ccv3.Warnings{"some-warning-1", "some-warning-2"},
   137  						nil)
   138  				})
   139  
   140  				It("Returns the proper buildpack", func() {
   141  					Expect(executeErr).ToNot(HaveOccurred())
   142  					Expect(warnings).To(ConsistOf("some-warning-1", "some-warning-2"))
   143  					Expect(buildpack).To(Equal(Buildpack{Name: "my-buildpack", GUID: "some-guid"}))
   144  				})
   145  
   146  				It("Does not pass a stack query to the client", func() {
   147  					Expect(fakeCloudControllerClient.GetBuildpacksCallCount()).To(Equal(1))
   148  					queries := fakeCloudControllerClient.GetBuildpacksArgsForCall(0)
   149  					Expect(queries).To(ConsistOf(
   150  						ccv3.Query{
   151  							Key:    ccv3.NameFilter,
   152  							Values: []string{buildpackName},
   153  						},
   154  					))
   155  				})
   156  			})
   157  
   158  			When("A stack is specified", func() {
   159  				BeforeEach(func() {
   160  					buildpackStack = "good-stack"
   161  					buildpackName = "my-buildpack"
   162  
   163  					ccBuildpack := ccv3.Buildpack{Name: "my-buildpack", GUID: "some-guid", Stack: "good-stack"}
   164  					fakeCloudControllerClient.GetBuildpacksReturns(
   165  						[]ccv3.Buildpack{ccBuildpack},
   166  						ccv3.Warnings{"some-warning-1", "some-warning-2"},
   167  						nil)
   168  				})
   169  
   170  				It("Returns the proper buildpack", func() {
   171  					Expect(executeErr).ToNot(HaveOccurred())
   172  					Expect(warnings).To(ConsistOf("some-warning-1", "some-warning-2"))
   173  					Expect(buildpack).To(Equal(Buildpack{Name: "my-buildpack", GUID: "some-guid", Stack: "good-stack"}))
   174  				})
   175  
   176  				It("Does pass a stack query to the client", func() {
   177  					Expect(fakeCloudControllerClient.GetBuildpacksCallCount()).To(Equal(1))
   178  					queries := fakeCloudControllerClient.GetBuildpacksArgsForCall(0)
   179  					Expect(queries).To(ConsistOf(
   180  						ccv3.Query{
   181  							Key:    ccv3.NameFilter,
   182  							Values: []string{buildpackName},
   183  						},
   184  						ccv3.Query{
   185  							Key:    ccv3.StackFilter,
   186  							Values: []string{buildpackStack},
   187  						},
   188  					))
   189  				})
   190  			})
   191  		})
   192  	})
   193  
   194  	Describe("GetBuildpacks", func() {
   195  		var (
   196  			buildpacks []Buildpack
   197  			warnings   Warnings
   198  			executeErr error
   199  		)
   200  
   201  		JustBeforeEach(func() {
   202  			buildpacks, warnings, executeErr = actor.GetBuildpacks()
   203  		})
   204  
   205  		When("getting buildpacks fails", func() {
   206  			BeforeEach(func() {
   207  				fakeCloudControllerClient.GetBuildpacksReturns(
   208  					nil,
   209  					ccv3.Warnings{"some-warning-1", "some-warning-2"},
   210  					errors.New("some-error"))
   211  			})
   212  
   213  			It("returns warnings and error", func() {
   214  				Expect(executeErr).To(MatchError("some-error"))
   215  				Expect(warnings).To(ConsistOf("some-warning-1", "some-warning-2"))
   216  			})
   217  		})
   218  
   219  		When("getting buildpacks is successful", func() {
   220  			BeforeEach(func() {
   221  				ccBuildpacks := []ccv3.Buildpack{
   222  					{Name: "buildpack-1", Position: types.NullInt{Value: 1, IsSet: true}},
   223  					{Name: "buildpack-2", Position: types.NullInt{Value: 2, IsSet: true}},
   224  				}
   225  
   226  				fakeCloudControllerClient.GetBuildpacksReturns(
   227  					ccBuildpacks,
   228  					ccv3.Warnings{"some-warning-1", "some-warning-2"},
   229  					nil)
   230  			})
   231  
   232  			It("returns the buildpacks and warnings", func() {
   233  				Expect(executeErr).ToNot(HaveOccurred())
   234  				Expect(warnings).To(ConsistOf("some-warning-1", "some-warning-2"))
   235  				Expect(buildpacks).To(Equal([]Buildpack{
   236  					{Name: "buildpack-1", Position: types.NullInt{Value: 1, IsSet: true}},
   237  					{Name: "buildpack-2", Position: types.NullInt{Value: 2, IsSet: true}},
   238  				}))
   239  
   240  				Expect(fakeCloudControllerClient.GetBuildpacksCallCount()).To(Equal(1))
   241  				Expect(fakeCloudControllerClient.GetBuildpacksArgsForCall(0)).To(ConsistOf(ccv3.Query{
   242  					Key:    ccv3.OrderBy,
   243  					Values: []string{ccv3.PositionOrder},
   244  				}))
   245  			})
   246  		})
   247  	})
   248  
   249  	Describe("CreateBuildpack", func() {
   250  		var (
   251  			buildpack  Buildpack
   252  			warnings   Warnings
   253  			executeErr error
   254  			bp         Buildpack
   255  		)
   256  
   257  		JustBeforeEach(func() {
   258  			buildpack, warnings, executeErr = actor.CreateBuildpack(bp)
   259  		})
   260  
   261  		When("creating a buildpack fails", func() {
   262  			BeforeEach(func() {
   263  				fakeCloudControllerClient.CreateBuildpackReturns(
   264  					ccv3.Buildpack{},
   265  					ccv3.Warnings{"some-warning-1", "some-warning-2"},
   266  					errors.New("some-error"))
   267  			})
   268  
   269  			It("returns warnings and error", func() {
   270  				Expect(executeErr).To(MatchError("some-error"))
   271  				Expect(warnings).To(ConsistOf("some-warning-1", "some-warning-2"))
   272  				Expect(buildpack).To(Equal(Buildpack{}))
   273  			})
   274  		})
   275  
   276  		When("creating a buildpack is successful", func() {
   277  			var returnBuildpack Buildpack
   278  			BeforeEach(func() {
   279  				bp = Buildpack{Name: "some-name", Stack: "some-stack"}
   280  				returnBuildpack = Buildpack{GUID: "some-guid", Name: "some-name", Stack: "some-stack"}
   281  				fakeCloudControllerClient.CreateBuildpackReturns(
   282  					ccv3.Buildpack(returnBuildpack),
   283  					ccv3.Warnings{"some-warning-1", "some-warning-2"},
   284  					nil)
   285  			})
   286  
   287  			It("returns the buildpacks and warnings", func() {
   288  				Expect(executeErr).ToNot(HaveOccurred())
   289  				Expect(warnings).To(ConsistOf("some-warning-1", "some-warning-2"))
   290  				Expect(buildpack).To(Equal(returnBuildpack))
   291  
   292  				Expect(fakeCloudControllerClient.CreateBuildpackCallCount()).To(Equal(1))
   293  				Expect(fakeCloudControllerClient.CreateBuildpackArgsForCall(0)).To(Equal(ccv3.Buildpack(bp)))
   294  			})
   295  		})
   296  	})
   297  
   298  	Describe("UpdateBuildpackByNameAndStack", func() {
   299  		var (
   300  			buildpackName  = "my-buidpack"
   301  			buildpackStack = "my-stack"
   302  			buildpack      = Buildpack{
   303  				Stack: "new-stack",
   304  			}
   305  
   306  			retBuildpack Buildpack
   307  			warnings     Warnings
   308  			executeErr   error
   309  		)
   310  
   311  		JustBeforeEach(func() {
   312  			retBuildpack, warnings, executeErr = actor.UpdateBuildpackByNameAndStack(buildpackName, buildpackStack, buildpack)
   313  		})
   314  
   315  		When("it is successful", func() {
   316  			var updatedBuildpack Buildpack
   317  			BeforeEach(func() {
   318  				foundBuildpack := ccv3.Buildpack{GUID: "a guid", Stack: ""}
   319  				updatedBuildpack = Buildpack{GUID: "a guid", Stack: "new-stack"}
   320  				fakeCloudControllerClient.GetBuildpacksReturns([]ccv3.Buildpack{foundBuildpack}, ccv3.Warnings{"warning-1"}, nil)
   321  				fakeCloudControllerClient.UpdateBuildpackReturns(ccv3.Buildpack(updatedBuildpack), ccv3.Warnings{"warning-2"}, nil)
   322  			})
   323  
   324  			It("returns the updated buildpack and warnings", func() {
   325  				Expect(executeErr).ToNot(HaveOccurred())
   326  				Expect(warnings).To(ConsistOf("warning-1", "warning-2"))
   327  				Expect(retBuildpack).To(Equal(updatedBuildpack))
   328  
   329  				queries := fakeCloudControllerClient.GetBuildpacksArgsForCall(0)
   330  				Expect(queries).To(ConsistOf(
   331  					ccv3.Query{
   332  						Key:    ccv3.NameFilter,
   333  						Values: []string{buildpackName},
   334  					},
   335  					ccv3.Query{
   336  						Key:    ccv3.StackFilter,
   337  						Values: []string{buildpackStack},
   338  					},
   339  				))
   340  
   341  				paramBuildpack := fakeCloudControllerClient.UpdateBuildpackArgsForCall(0)
   342  				Expect(paramBuildpack).To(Equal(ccv3.Buildpack{
   343  					GUID:  "a guid",
   344  					Stack: "new-stack",
   345  				}))
   346  			})
   347  		})
   348  
   349  		When("The get fails", func() {
   350  			BeforeEach(func() {
   351  				fakeCloudControllerClient.GetBuildpacksReturns([]ccv3.Buildpack{}, ccv3.Warnings{"warning-1"}, errors.New("whoops"))
   352  			})
   353  
   354  			It("returns the error and warnings", func() {
   355  				Expect(executeErr).To(HaveOccurred())
   356  				Expect(warnings).To(ConsistOf("warning-1"))
   357  				Expect(retBuildpack).To(Equal(Buildpack{}))
   358  			})
   359  		})
   360  
   361  		When("The update fails", func() {
   362  			BeforeEach(func() {
   363  				ccBuildpack := ccv3.Buildpack{GUID: "a guid", Stack: "old-stack"}
   364  				fakeCloudControllerClient.GetBuildpacksReturns([]ccv3.Buildpack{ccBuildpack}, ccv3.Warnings{"warning-1"}, nil)
   365  				fakeCloudControllerClient.UpdateBuildpackReturns(ccv3.Buildpack{}, ccv3.Warnings{"warning-2"}, errors.New("whoops"))
   366  			})
   367  
   368  			It("returns the error and warnings", func() {
   369  				Expect(executeErr).To(HaveOccurred())
   370  				Expect(warnings).To(ConsistOf("warning-1", "warning-2"))
   371  				Expect(retBuildpack).To(Equal(Buildpack{}))
   372  			})
   373  		})
   374  
   375  	})
   376  
   377  	Describe("UploadBuildpack", func() {
   378  		var (
   379  			bpFile     io.Reader
   380  			bpFilePath string
   381  			fakePb     *v7actionfakes.FakeSimpleProgressBar
   382  
   383  			jobURL     ccv3.JobURL
   384  			warnings   Warnings
   385  			executeErr error
   386  		)
   387  
   388  		BeforeEach(func() {
   389  			bpFile = strings.NewReader("")
   390  			fakePb = new(v7actionfakes.FakeSimpleProgressBar)
   391  			fakePb.InitializeReturns(bpFile, 66, nil)
   392  		})
   393  
   394  		JustBeforeEach(func() {
   395  			bpFilePath = "tmp/buildpack.zip"
   396  			jobURL, warnings, executeErr = actor.UploadBuildpack("some-bp-guid", bpFilePath, fakePb)
   397  		})
   398  
   399  		It("tracks the progress of the upload", func() {
   400  			Expect(executeErr).ToNot(HaveOccurred())
   401  			Expect(fakePb.InitializeCallCount()).To(Equal(1))
   402  			Expect(fakePb.InitializeArgsForCall(0)).To(Equal(bpFilePath))
   403  			Expect(fakePb.TerminateCallCount()).To(Equal(1))
   404  		})
   405  
   406  		When("reading the file errors", func() {
   407  			BeforeEach(func() {
   408  				fakePb.InitializeReturns(bpFile, 66, os.ErrNotExist)
   409  			})
   410  
   411  			It("returns the err", func() {
   412  				Expect(executeErr).To(Equal(os.ErrNotExist))
   413  			})
   414  		})
   415  
   416  		When("the upload errors", func() {
   417  			BeforeEach(func() {
   418  				fakeCloudControllerClient.UploadBuildpackReturns(
   419  					ccv3.JobURL(""),
   420  					ccv3.Warnings{"some-upload-warning"},
   421  					errors.New("some-upload-error"),
   422  				)
   423  			})
   424  
   425  			It("returns warnings and errors", func() {
   426  				Expect(warnings).To(ConsistOf("some-upload-warning"))
   427  				Expect(executeErr).To(MatchError("some-upload-error"))
   428  			})
   429  		})
   430  
   431  		When("the cc returns an error because the buildpack and stack combo already exists", func() {
   432  			BeforeEach(func() {
   433  				fakeCloudControllerClient.UploadBuildpackReturns(
   434  					ccv3.JobURL(""),
   435  					ccv3.Warnings{"some-upload-warning"},
   436  					ccerror.BuildpackAlreadyExistsForStackError{Message: "ya blew it"},
   437  				)
   438  			})
   439  
   440  			It("returns warnings and a BuildpackAlreadyExistsForStackError", func() {
   441  				Expect(warnings).To(ConsistOf("some-upload-warning"))
   442  				Expect(executeErr).To(MatchError(actionerror.BuildpackAlreadyExistsForStackError{Message: "ya blew it"}))
   443  			})
   444  		})
   445  
   446  		When("the upload is successful", func() {
   447  			BeforeEach(func() {
   448  				fakeCloudControllerClient.UploadBuildpackReturns(
   449  					ccv3.JobURL("http://example.com/some-job-url"),
   450  					ccv3.Warnings{"some-create-warning"},
   451  					nil,
   452  				)
   453  			})
   454  
   455  			It("uploads the buildpack and returns the Job URL and any warnings", func() {
   456  				Expect(executeErr).ToNot(HaveOccurred())
   457  				Expect(fakeCloudControllerClient.UploadBuildpackCallCount()).To(Equal(1))
   458  				guid, path, pbReader, size := fakeCloudControllerClient.UploadBuildpackArgsForCall(0)
   459  				Expect(guid).To(Equal("some-bp-guid"))
   460  				Expect(size).To(Equal(int64(66)))
   461  				Expect(path).To(Equal(bpFilePath))
   462  				Expect(pbReader).To(Equal(bpFile))
   463  				Expect(jobURL).To(Equal(ccv3.JobURL("http://example.com/some-job-url")))
   464  				Expect(warnings).To(ConsistOf("some-create-warning"))
   465  			})
   466  		})
   467  	})
   468  
   469  	Describe("PrepareBuildpackBits", func() {
   470  		var (
   471  			inPath         string
   472  			outPath        string
   473  			tmpDirPath     string
   474  			fakeDownloader *v7actionfakes.FakeDownloader
   475  
   476  			executeErr error
   477  		)
   478  
   479  		BeforeEach(func() {
   480  			fakeDownloader = new(v7actionfakes.FakeDownloader)
   481  		})
   482  
   483  		JustBeforeEach(func() {
   484  			outPath, executeErr = actor.PrepareBuildpackBits(inPath, tmpDirPath, fakeDownloader)
   485  		})
   486  
   487  		When("the buildpack path is a url", func() {
   488  			BeforeEach(func() {
   489  				inPath = "http://buildpacks.com/a.zip"
   490  				fakeDownloader = new(v7actionfakes.FakeDownloader)
   491  
   492  				var err error
   493  				tmpDirPath, err = ioutil.TempDir("", "buildpackdir-")
   494  				Expect(err).ToNot(HaveOccurred())
   495  			})
   496  
   497  			AfterEach(func() {
   498  				Expect(os.RemoveAll(tmpDirPath)).ToNot(HaveOccurred())
   499  			})
   500  
   501  			When("downloading the file succeeds", func() {
   502  				BeforeEach(func() {
   503  					fakeDownloader.DownloadReturns("/tmp/buildpackdir-100/a.zip", nil)
   504  				})
   505  
   506  				It("downloads the buildpack to a local file", func() {
   507  					Expect(executeErr).ToNot(HaveOccurred())
   508  					Expect(fakeDownloader.DownloadCallCount()).To(Equal(1))
   509  
   510  					inputPath, inputTmpDirPath := fakeDownloader.DownloadArgsForCall(0)
   511  					Expect(inputPath).To(Equal("http://buildpacks.com/a.zip"))
   512  					Expect(inputTmpDirPath).To(Equal(tmpDirPath))
   513  				})
   514  			})
   515  
   516  			When("downloading the file fails", func() {
   517  				BeforeEach(func() {
   518  					fakeDownloader.DownloadReturns("", errors.New("some-download-error"))
   519  				})
   520  
   521  				It("returns the error", func() {
   522  					Expect(executeErr).To(MatchError("some-download-error"))
   523  				})
   524  			})
   525  		})
   526  
   527  		When("the buildpack path points to a directory", func() {
   528  			var tempFile *os.File
   529  			BeforeEach(func() {
   530  				var err error
   531  				inPath, err = ioutil.TempDir("", "buildpackdir-")
   532  				Expect(err).ToNot(HaveOccurred())
   533  
   534  				tempFile, err = ioutil.TempFile(inPath, "foo")
   535  				Expect(err).ToNot(HaveOccurred())
   536  
   537  				tmpDirPath, err = ioutil.TempDir("", "buildpackdir-")
   538  				Expect(err).ToNot(HaveOccurred())
   539  			})
   540  
   541  			AfterEach(func() {
   542  				tempFile.Close()
   543  				Expect(os.RemoveAll(inPath)).ToNot(HaveOccurred())
   544  				Expect(os.RemoveAll(tmpDirPath)).ToNot(HaveOccurred())
   545  			})
   546  
   547  			It("returns a path to the zipped directory", func() {
   548  				Expect(executeErr).ToNot(HaveOccurred())
   549  				Expect(fakeDownloader.DownloadCallCount()).To(Equal(0))
   550  
   551  				Expect(filepath.Base(outPath)).To(Equal(filepath.Base(inPath) + ".zip"))
   552  			})
   553  		})
   554  
   555  		When("the buildpack path points to an empty directory", func() {
   556  			BeforeEach(func() {
   557  				var err error
   558  				inPath, err = ioutil.TempDir("", "some-empty-dir")
   559  				Expect(err).ToNot(HaveOccurred())
   560  
   561  				tmpDirPath, err = ioutil.TempDir("", "buildpackdir-")
   562  				Expect(err).ToNot(HaveOccurred())
   563  			})
   564  
   565  			AfterEach(func() {
   566  				Expect(os.RemoveAll(inPath)).ToNot(HaveOccurred())
   567  				Expect(os.RemoveAll(tmpDirPath)).ToNot(HaveOccurred())
   568  			})
   569  
   570  			It("returns an error", func() {
   571  				Expect(executeErr).To(MatchError(actionerror.EmptyBuildpackDirectoryError{Path: inPath}))
   572  			})
   573  		})
   574  
   575  		When("the buildpack path points to a zip file", func() {
   576  			BeforeEach(func() {
   577  				inPath = "/foo/buildpacks/a.zip"
   578  			})
   579  
   580  			It("returns the local filepath", func() {
   581  				Expect(executeErr).ToNot(HaveOccurred())
   582  				Expect(fakeDownloader.DownloadCallCount()).To(Equal(0))
   583  				Expect(outPath).To(Equal("/foo/buildpacks/a.zip"))
   584  			})
   585  		})
   586  	})
   587  
   588  	Describe("Zipit", func() {
   589  		//tested in buildpack_linux_test.go and buildpack_windows_test.go
   590  		var (
   591  			source string
   592  			target string
   593  
   594  			executeErr error
   595  		)
   596  
   597  		JustBeforeEach(func() {
   598  			executeErr = Zipit(source, target, "testzip-")
   599  		})
   600  
   601  		When("the source directory does not exist", func() {
   602  			BeforeEach(func() {
   603  				source = ""
   604  				target = ""
   605  			})
   606  
   607  			It("returns an error", func() {
   608  				Expect(os.IsNotExist(executeErr)).To(BeTrue())
   609  			})
   610  		})
   611  	})
   612  
   613  	Describe("DeleteBuildpackByNameAndStack", func() {
   614  		var (
   615  			buildpackName  = "buildpack-name"
   616  			buildpackStack = "buildpack-stack"
   617  			buildpackGUID  = "buildpack-guid"
   618  			jobURL         = "buildpack-delete-job-url"
   619  			warnings       Warnings
   620  			executeErr     error
   621  		)
   622  
   623  		JustBeforeEach(func() {
   624  			warnings, executeErr = actor.DeleteBuildpackByNameAndStack(buildpackName, buildpackStack)
   625  		})
   626  
   627  		When("getting the buildpack fails", func() {
   628  			BeforeEach(func() {
   629  				fakeCloudControllerClient.GetBuildpacksReturns(
   630  					[]ccv3.Buildpack{},
   631  					ccv3.Warnings{"some-warning-1", "some-warning-2"},
   632  					errors.New("api-get-error"))
   633  			})
   634  			It("returns warnings and error", func() {
   635  				Expect(executeErr).To(MatchError("api-get-error"))
   636  				Expect(warnings).To(ConsistOf("some-warning-1", "some-warning-2"))
   637  				Expect(fakeCloudControllerClient.GetBuildpacksCallCount()).To(Equal(1))
   638  				queries := fakeCloudControllerClient.GetBuildpacksArgsForCall(0)
   639  				Expect(queries).To(ConsistOf(
   640  					ccv3.Query{
   641  						Key:    ccv3.NameFilter,
   642  						Values: []string{buildpackName},
   643  					},
   644  					ccv3.Query{
   645  						Key:    ccv3.StackFilter,
   646  						Values: []string{buildpackStack},
   647  					},
   648  				))
   649  			})
   650  		})
   651  
   652  		When("getting the buildpack succeeds", func() {
   653  			BeforeEach(func() {
   654  				fakeCloudControllerClient.GetBuildpacksReturns(
   655  					[]ccv3.Buildpack{{GUID: buildpackGUID, Name: buildpackName, Stack: buildpackStack}},
   656  					ccv3.Warnings{"some-warning-1", "some-warning-2"},
   657  					nil)
   658  			})
   659  			When("deleting a buildpack fails", func() {
   660  				BeforeEach(func() {
   661  					fakeCloudControllerClient.DeleteBuildpackReturns(
   662  						"",
   663  						ccv3.Warnings{"some-warning-3", "some-warning-4"},
   664  						errors.New("api-delete-error"))
   665  				})
   666  
   667  				It("returns warnings and error", func() {
   668  					Expect(executeErr).To(MatchError("api-delete-error"))
   669  					Expect(warnings).To(ConsistOf("some-warning-1", "some-warning-2", "some-warning-3", "some-warning-4"))
   670  					Expect(fakeCloudControllerClient.DeleteBuildpackCallCount()).To(Equal(1))
   671  					paramGUID := fakeCloudControllerClient.DeleteBuildpackArgsForCall(0)
   672  					Expect(paramGUID).To(Equal(buildpackGUID))
   673  				})
   674  			})
   675  
   676  			When("deleting the buildpack is successful", func() {
   677  				BeforeEach(func() {
   678  					fakeCloudControllerClient.DeleteBuildpackReturns(
   679  						ccv3.JobURL(jobURL),
   680  						ccv3.Warnings{"some-warning-3", "some-warning-4"},
   681  						nil)
   682  				})
   683  
   684  				When("polling the job fails", func() {
   685  					BeforeEach(func() {
   686  						fakeCloudControllerClient.PollJobReturns(
   687  							ccv3.Warnings{"some-warning-5", "some-warning-6"},
   688  							errors.New("api-poll-job-error"))
   689  					})
   690  					It("returns warnings and an error", func() {
   691  						Expect(executeErr).To(MatchError("api-poll-job-error"))
   692  						Expect(warnings).To(ConsistOf("some-warning-1", "some-warning-2", "some-warning-3", "some-warning-4", "some-warning-5", "some-warning-6"))
   693  						Expect(fakeCloudControllerClient.PollJobCallCount()).To(Equal(1))
   694  						paramURL := fakeCloudControllerClient.PollJobArgsForCall(0)
   695  						Expect(paramURL).To(Equal(ccv3.JobURL(jobURL)))
   696  					})
   697  				})
   698  
   699  				When("polling the job succeeds", func() {
   700  					BeforeEach(func() {
   701  						fakeCloudControllerClient.PollJobReturns(
   702  							ccv3.Warnings{"some-warning-5", "some-warning-6"},
   703  							nil)
   704  					})
   705  					It("returns all warnings and no error", func() {
   706  						Expect(executeErr).ToNot(HaveOccurred())
   707  						Expect(warnings).To(ConsistOf("some-warning-1", "some-warning-2", "some-warning-3", "some-warning-4", "some-warning-5", "some-warning-6"))
   708  						Expect(fakeCloudControllerClient.PollJobCallCount()).To(Equal(1))
   709  						paramURL := fakeCloudControllerClient.PollJobArgsForCall(0)
   710  						Expect(paramURL).To(Equal(ccv3.JobURL(jobURL)))
   711  
   712  					})
   713  				})
   714  			})
   715  		})
   716  
   717  	})
   718  })