github.com/willmadison/cli@v6.40.1-0.20181018160101-29d5937903ff+incompatible/integration/shared/global/create_buildpack_command_test.go (about)

     1  package global
     2  
     3  import (
     4  	"bytes"
     5  	"io/ioutil"
     6  	"log"
     7  	"net/http"
     8  	"os"
     9  	"regexp"
    10  
    11  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccversion"
    12  	"code.cloudfoundry.org/cli/integration/helpers"
    13  
    14  	. "github.com/onsi/ginkgo"
    15  	. "github.com/onsi/gomega"
    16  	. "github.com/onsi/gomega/gbytes"
    17  	. "github.com/onsi/gomega/gexec"
    18  	. "github.com/onsi/gomega/ghttp"
    19  )
    20  
    21  var _ = Describe("create buildpack command", func() {
    22  	var (
    23  		buildpackName string
    24  		username      string
    25  	)
    26  
    27  	BeforeEach(func() {
    28  		buildpackName = helpers.NewBuildpackName()
    29  	})
    30  
    31  	Describe("help", func() {
    32  		When("--help flag is set", func() {
    33  			It("Displays command usage to output", func() {
    34  				session := helpers.CF("create-buildpack", "--help")
    35  				Eventually(session).Should(Say("NAME:"))
    36  				Eventually(session).Should(Say("create-buildpack - Create a buildpack"))
    37  				Eventually(session).Should(Say("USAGE:"))
    38  				Eventually(session).Should(Say("cf create-buildpack BUILDPACK PATH POSITION \\[--enable|--disable\\]"))
    39  				Eventually(session).Should(Say("TIP:"))
    40  				Eventually(session).Should(Say("Path should be a zip file, a url to a zip file, or a local directory. Position is a positive integer, sets priority, and is sorted from lowest to highest."))
    41  				Eventually(session).Should(Say("OPTIONS:"))
    42  				Eventually(session).Should(Say("--disable\\s+Disable the buildpack from being used for staging"))
    43  				Eventually(session).Should(Say("--enable\\s+Enable the buildpack to be used for staging"))
    44  				Eventually(session).Should(Say("SEE ALSO:"))
    45  				Eventually(session).Should(Say("buildpacks, push"))
    46  				Eventually(session).Should(Exit(0))
    47  			})
    48  		})
    49  	})
    50  
    51  	When("the environment is not setup correctly", func() {
    52  		It("fails with the appropriate errors", func() {
    53  			path, err := os.Getwd()
    54  			Expect(err).ToNot(HaveOccurred())
    55  
    56  			helpers.CheckEnvironmentTargetedCorrectly(false, false, ReadOnlyOrg, "create-buildpack", "fake-buildpack", path, "1")
    57  		})
    58  	})
    59  
    60  	When("the user is logged in", func() {
    61  		BeforeEach(func() {
    62  			helpers.LoginCF()
    63  			username, _ = helpers.GetCredentials()
    64  		})
    65  
    66  		When("uploading from a directory", func() {
    67  			var buildpackDir string
    68  
    69  			AfterEach(func() {
    70  				err := os.RemoveAll(buildpackDir)
    71  				Expect(err).ToNot(HaveOccurred())
    72  			})
    73  
    74  			When("zipping the directory errors", func() {
    75  				BeforeEach(func() {
    76  					buildpackDir = "some/nonexistent/dir"
    77  				})
    78  
    79  				It("returns an error", func() {
    80  					session := helpers.CF("create-buildpack", buildpackName, buildpackDir, "1")
    81  					Eventually(session.Err).Should(Say("Incorrect Usage: The specified path 'some/nonexistent/dir' does not exist."))
    82  					Eventually(session).Should(Say("USAGE:"))
    83  					Eventually(session).Should(Exit(1))
    84  				})
    85  			})
    86  
    87  			When("zipping the directory succeeds", func() {
    88  				BeforeEach(func() {
    89  					var err error
    90  					buildpackDir, err = ioutil.TempDir("", "buildpackdir-")
    91  					Expect(err).ToNot(HaveOccurred())
    92  					file, err := ioutil.TempFile(buildpackDir, "myfile-")
    93  					defer file.Close()
    94  					Expect(err).ToNot(HaveOccurred())
    95  				})
    96  
    97  				It("successfully uploads a buildpack", func() {
    98  					session := helpers.CF("create-buildpack", buildpackName, buildpackDir, "1")
    99  					Eventually(session).Should(Say("Creating buildpack %s as %s\\.\\.\\.", buildpackName, username))
   100  					Eventually(session).Should(Say("OK"))
   101  					Eventually(session).Should(Say("Uploading buildpack %s as %s\\.\\.\\.", buildpackName, username))
   102  					Eventually(session).Should(Say("Done uploading"))
   103  					Eventually(session).Should(Say("OK"))
   104  					Eventually(session).Should(Exit(0))
   105  				})
   106  			})
   107  
   108  			When("the specified directory is empty", func() {
   109  				BeforeEach(func() {
   110  					var err error
   111  					buildpackDir, err = ioutil.TempDir("", "empty-")
   112  					Expect(err).ToNot(HaveOccurred())
   113  				})
   114  
   115  				It("fails and reports that the directory is empty", func() {
   116  					session := helpers.CF("create-buildpack", buildpackName, buildpackDir, "1")
   117  					Eventually(session).Should(Say("Creating buildpack %s as %s\\.\\.\\.", buildpackName, username))
   118  					Eventually(session.Err).Should(Say("The specified path '%s' cannot be an empty directory.", regexp.QuoteMeta(buildpackDir)))
   119  					Eventually(session).Should(Say("FAILED"))
   120  					Eventually(session).Should(Exit(1))
   121  				})
   122  			})
   123  		})
   124  
   125  		When("uploading from a zip", func() {
   126  			var stacks []string
   127  
   128  			BeforeEach(func() {
   129  				stacks = helpers.EnsureMinimumNumberOfStacks(2)
   130  			})
   131  
   132  			When("specifying a valid path", func() {
   133  				When("the new buildpack is unique", func() {
   134  					When("the new buildpack has a nil stack", func() {
   135  						It("successfully uploads a buildpack", func() {
   136  							helpers.BuildpackWithoutStack(func(buildpackPath string) {
   137  								session := helpers.CF("create-buildpack", buildpackName, buildpackPath, "1")
   138  								Eventually(session).Should(Say("Creating buildpack %s as %s\\.\\.\\.", buildpackName, username))
   139  								Eventually(session).Should(Say("OK"))
   140  								Eventually(session).Should(Say("Uploading buildpack %s as %s\\.\\.\\.", buildpackName, username))
   141  								Eventually(session).Should(Say("Done uploading"))
   142  								Eventually(session).Should(Say("OK"))
   143  								Eventually(session).Should(Exit(0))
   144  							})
   145  
   146  							session := helpers.CF("buildpacks")
   147  							Eventually(session).Should(Say(helpers.BuildpacksOutputRegex(helpers.BuildpackFields{
   148  								Name: buildpackName, Position: "1"})))
   149  							Eventually(session).Should(Exit(0))
   150  						})
   151  					})
   152  
   153  					When("the new buildpack has a valid stack", func() {
   154  						BeforeEach(func() {
   155  							helpers.SkipIfVersionLessThan(ccversion.MinVersionBuildpackStackAssociationV2)
   156  						})
   157  
   158  						It("successfully uploads a buildpack", func() {
   159  							helpers.BuildpackWithStack(func(buildpackPath string) {
   160  								session := helpers.CF("create-buildpack", buildpackName, buildpackPath, "1")
   161  								Eventually(session).Should(Say("Creating buildpack %s as %s\\.\\.\\.", buildpackName, username))
   162  								Eventually(session).Should(Say("OK"))
   163  								Eventually(session).Should(Say("Uploading buildpack %s as %s\\.\\.\\.", buildpackName, username))
   164  								Eventually(session).Should(Say("Done uploading"))
   165  								Eventually(session).Should(Say("OK"))
   166  								Eventually(session).Should(Exit(0))
   167  							}, stacks[0])
   168  
   169  							session := helpers.CF("buildpacks")
   170  							Eventually(session).Should(Say(helpers.BuildpacksOutputRegex(helpers.BuildpackFields{
   171  								Name: buildpackName, Stack: stacks[0], Position: "1",
   172  							})))
   173  							Eventually(session).Should(Exit(0))
   174  						})
   175  					})
   176  				})
   177  
   178  				When("the new buildpack has an invalid stack", func() {
   179  					BeforeEach(func() {
   180  						helpers.SkipIfVersionLessThan(ccversion.MinVersionBuildpackStackAssociationV2)
   181  					})
   182  
   183  					It("returns the appropriate error", func() {
   184  						helpers.BuildpackWithStack(func(buildpackPath string) {
   185  							session := helpers.CF("create-buildpack", buildpackName, buildpackPath, "1")
   186  							Eventually(session).Should(Say("Creating buildpack %s as %s\\.\\.\\.", buildpackName, username))
   187  							Eventually(session).Should(Say("OK"))
   188  							Eventually(session).Should(Say("Uploading buildpack %s as %s\\.\\.\\.", buildpackName, username))
   189  							Eventually(session.Err).Should(Say("Uploaded buildpack stack \\(fake-stack\\) does not exist"))
   190  							Eventually(session).Should(Exit(1))
   191  						}, "fake-stack")
   192  					})
   193  				})
   194  
   195  				When("a buildpack with the same name exists", func() {
   196  					var (
   197  						existingBuildpack string
   198  					)
   199  
   200  					BeforeEach(func() {
   201  						existingBuildpack = buildpackName
   202  					})
   203  
   204  					When("the new buildpack has a nil stack", func() {
   205  						BeforeEach(func() {
   206  							helpers.SkipIfVersionLessThan(ccversion.MinVersionBuildpackStackAssociationV2)
   207  						})
   208  
   209  						When("the existing buildpack does not have a nil stack", func() {
   210  							BeforeEach(func() {
   211  								helpers.BuildpackWithStack(func(buildpackPath string) {
   212  									session := helpers.CF("create-buildpack", existingBuildpack, buildpackPath, "5")
   213  									Eventually(session).Should(Exit(0))
   214  								}, stacks[0])
   215  							})
   216  
   217  							It("successfully uploads a buildpack", func() {
   218  								helpers.BuildpackWithStack(func(buildpackPath string) {
   219  									session := helpers.CF("create-buildpack", buildpackName, buildpackPath, "1")
   220  									Eventually(session).Should(Say("Creating buildpack %s as %s\\.\\.\\.", buildpackName, username))
   221  									Eventually(session).Should(Say("OK"))
   222  									Eventually(session).Should(Say("Uploading buildpack %s as %s\\.\\.\\.", buildpackName, username))
   223  									Eventually(session).Should(Exit(0))
   224  								}, stacks[0])
   225  
   226  								session := helpers.CF("buildpacks")
   227  								Eventually(session).Should(Say(helpers.BuildpacksOutputRegex(helpers.BuildpackFields{
   228  									Name: buildpackName, Position: "1"})))
   229  								Eventually(session).Should(Say(helpers.BuildpacksOutputRegex(helpers.BuildpackFields{
   230  									Name: existingBuildpack, Stack: stacks[0], Position: "6"})))
   231  								Eventually(session).Should(Exit(0))
   232  							})
   233  						})
   234  
   235  						When("the existing buildpack has a nil stack", func() {
   236  							BeforeEach(func() {
   237  								helpers.BuildpackWithoutStack(func(buildpackPath string) {
   238  									session := helpers.CF("create-buildpack", existingBuildpack, buildpackPath, "5")
   239  									Eventually(session).Should(Exit(0))
   240  								})
   241  							})
   242  
   243  							It("prints a warning but exits 0", func() {
   244  								helpers.BuildpackWithoutStack(func(buildpackPath string) {
   245  									session := helpers.CF("create-buildpack", buildpackName, buildpackPath, "1")
   246  									Eventually(session).Should(Say("Creating buildpack %s as %s\\.\\.\\.", buildpackName, username))
   247  									Eventually(session.Err).Should(Say("Buildpack %s already exists without a stack", buildpackName))
   248  									Eventually(session).Should(Exit(0))
   249  								})
   250  
   251  								session := helpers.CF("buildpacks")
   252  								Eventually(session).Should(Say(`%s\s+5`, existingBuildpack))
   253  								Eventually(session).Should(Exit(0))
   254  							})
   255  						})
   256  					})
   257  
   258  					When("the new buildpack has a non-nil stack", func() {
   259  						BeforeEach(func() {
   260  							helpers.SkipIfVersionLessThan(ccversion.MinVersionBuildpackStackAssociationV2)
   261  						})
   262  
   263  						When("the existing buildpack has a different non-nil stack", func() {
   264  							BeforeEach(func() {
   265  								helpers.BuildpackWithStack(func(buildpackPath string) {
   266  									session := helpers.CF("create-buildpack", existingBuildpack, buildpackPath, "5")
   267  									Eventually(session).Should(Exit(0))
   268  								}, stacks[1])
   269  							})
   270  
   271  							It("successfully uploads a buildpack", func() {
   272  								helpers.BuildpackWithStack(func(buildpackPath string) {
   273  									session := helpers.CF("create-buildpack", buildpackName, buildpackPath, "1")
   274  									Eventually(session).Should(Say("Creating buildpack %s as %s\\.\\.\\.", buildpackName, username))
   275  									Eventually(session).Should(Say("OK"))
   276  									Eventually(session).Should(Say("Uploading buildpack %s as %s\\.\\.\\.", buildpackName, username))
   277  									Eventually(session).Should(Say("Done uploading"))
   278  									Eventually(session).Should(Say("OK"))
   279  									Eventually(session).Should(Exit(0))
   280  								}, stacks[0])
   281  
   282  								session := helpers.CF("buildpacks")
   283  								Eventually(session).Should(Say(helpers.BuildpacksOutputRegex(helpers.BuildpackFields{
   284  									Name: buildpackName, Stack: stacks[0]})))
   285  								Eventually(session).Should(Say(helpers.BuildpacksOutputRegex(helpers.BuildpackFields{
   286  									Name: existingBuildpack, Stack: stacks[1]})))
   287  								Eventually(session).Should(Exit(0))
   288  							})
   289  						})
   290  
   291  						When("the existing buildpack has a nil stack", func() {
   292  							BeforeEach(func() {
   293  								helpers.BuildpackWithoutStack(func(buildpackPath string) {
   294  									session := helpers.CF("create-buildpack", existingBuildpack, buildpackPath, "5")
   295  									Eventually(session).Should(Exit(0))
   296  								})
   297  							})
   298  
   299  							It("prints a warning and tip but exits 0", func() {
   300  								helpers.BuildpackWithStack(func(buildpackPath string) {
   301  									session := helpers.CF("create-buildpack", buildpackName, buildpackPath, "1")
   302  									Eventually(session).Should(Say("Creating buildpack %s as %s\\.\\.\\.", buildpackName, username))
   303  									Eventually(session.Err).Should(Say("Buildpack %s already exists without a stack", buildpackName))
   304  									Eventually(session).Should(Say("TIP: use 'cf buildpacks' and 'cf delete-buildpack' to delete buildpack %s without a stack", buildpackName))
   305  									Eventually(session).Should(Exit(0))
   306  								}, stacks[0])
   307  							})
   308  						})
   309  
   310  						When("the existing buildpack has the same non-nil stack", func() {
   311  							BeforeEach(func() {
   312  								helpers.BuildpackWithStack(func(buildpackPath string) {
   313  									session := helpers.CF("create-buildpack", existingBuildpack, buildpackPath, "5")
   314  									Eventually(session).Should(Exit(0))
   315  								}, stacks[0])
   316  							})
   317  
   318  							It("prints a warning but doesn't exit 1", func() {
   319  								helpers.BuildpackWithStack(func(buildpackPath string) {
   320  									session := helpers.CF("create-buildpack", buildpackName, buildpackPath, "1")
   321  									Eventually(session).Should(Say("Creating buildpack %s as %s\\.\\.\\.", buildpackName, username))
   322  									Eventually(session.Err).Should(Say("The buildpack name %s is already in use for the stack %s", buildpackName, stacks[0]))
   323  									Eventually(session).Should(Say("TIP: use 'cf update-buildpack' to update this buildpack"))
   324  									Eventually(session).Should(Exit(0))
   325  								}, stacks[0])
   326  							})
   327  						})
   328  					})
   329  
   330  					When("the API doesn't support stack association", func() {
   331  						BeforeEach(func() {
   332  							helpers.SkipIfVersionAtLeast(ccversion.MinVersionBuildpackStackAssociationV2)
   333  
   334  							helpers.BuildpackWithoutStack(func(buildpackPath string) {
   335  								session := helpers.CF("create-buildpack", existingBuildpack, buildpackPath, "5")
   336  								Eventually(session).Should(Exit(0))
   337  							})
   338  						})
   339  
   340  						It("prints a warning but doesn't exit 1", func() {
   341  							helpers.BuildpackWithoutStack(func(buildpackPath string) {
   342  								session := helpers.CF("create-buildpack", buildpackName, buildpackPath, "1")
   343  								Eventually(session.Err).Should(Say("Buildpack %s already exists", buildpackName))
   344  								Eventually(session).Should(Say("TIP: use 'cf update-buildpack' to update this buildpack"))
   345  								Eventually(session).Should(Exit(0))
   346  							})
   347  						})
   348  					})
   349  				})
   350  			})
   351  
   352  			When("specifying an invalid path", func() {
   353  				It("returns the appropriate error", func() {
   354  					session := helpers.CF("create-buildpack", buildpackName, "bogus-path", "1")
   355  
   356  					Eventually(session.Err).Should(Say("Incorrect Usage: The specified path 'bogus-path' does not exist"))
   357  					Eventually(session).Should(Say("USAGE:"))
   358  					Eventually(session).Should(Exit(1))
   359  				})
   360  			})
   361  		})
   362  
   363  		When("uploading from a URL", func() {
   364  			var buildpackURL string
   365  
   366  			When("specifying a valid URL", func() {
   367  				BeforeEach(func() {
   368  					buildpackURL = "https://github.com/cloudfoundry/binary-buildpack/releases/download/v1.0.21/binary-buildpack-v1.0.21.zip"
   369  				})
   370  
   371  				It("successfully uploads a buildpack", func() {
   372  					session := helpers.CF("create-buildpack", buildpackName, buildpackURL, "1")
   373  					Eventually(session).Should(Say("Creating buildpack %s as %s\\.\\.\\.", buildpackName, username))
   374  					Eventually(session).Should(Say("OK"))
   375  					Eventually(session).Should(Say("Uploading buildpack %s as %s\\.\\.\\.", buildpackName, username))
   376  					Eventually(session).Should(Say("Done uploading"))
   377  					Eventually(session).Should(Say("OK"))
   378  					Eventually(session).Should(Exit(0))
   379  				})
   380  			})
   381  
   382  			When("a 4xx or 5xx HTTP response status is encountered", func() {
   383  				var server *Server
   384  
   385  				BeforeEach(func() {
   386  					server = NewServer()
   387  					// Suppresses ginkgo server logs
   388  					server.HTTPTestServer.Config.ErrorLog = log.New(&bytes.Buffer{}, "", 0)
   389  					server.AppendHandlers(
   390  						CombineHandlers(
   391  							VerifyRequest(http.MethodGet, "/"),
   392  							RespondWith(http.StatusNotFound, nil),
   393  						),
   394  					)
   395  				})
   396  
   397  				AfterEach(func() {
   398  					server.Close()
   399  				})
   400  
   401  				It("displays an appropriate error", func() {
   402  					session := helpers.CF("create-buildpack", buildpackName, server.URL(), "10")
   403  					Eventually(session).Should(Say("Creating buildpack %s as %s\\.\\.\\.", buildpackName, username))
   404  					Eventually(session.Err).Should(Say("Download attempt failed; server returned 404 Not Found"))
   405  					Eventually(session.Err).Should(Say("Unable to install; buildpack is not available from the given URL\\."))
   406  					Eventually(session).Should(Say("FAILED"))
   407  					Eventually(session).Should(Exit(1))
   408  				})
   409  			})
   410  
   411  			When("specifying an invalid URL", func() {
   412  				BeforeEach(func() {
   413  					buildpackURL = "http://not-a-real-url"
   414  				})
   415  
   416  				It("returns the appropriate error", func() {
   417  					session := helpers.CF("create-buildpack", buildpackName, buildpackURL, "1")
   418  					Eventually(session).Should(Say("Creating buildpack %s as %s\\.\\.\\.", buildpackName, username))
   419  					Eventually(session.Err).Should(Say("Get %s: dial tcp: lookup", buildpackURL))
   420  					Eventually(session).Should(Say("FAILED"))
   421  					Eventually(session).Should(Exit(1))
   422  				})
   423  			})
   424  		})
   425  
   426  		When("specifying the position flag", func() {
   427  			When("position is positive integer", func() {
   428  				It("successfully uploads buildpack in correct position", func() {
   429  					helpers.BuildpackWithoutStack(func(buildpackPath string) {
   430  						session := helpers.CF("create-buildpack", buildpackName, buildpackPath, "3")
   431  						Eventually(session).Should(Say("Creating buildpack %s as %s\\.\\.\\.", buildpackName, username))
   432  						Eventually(session).Should(Say("OK"))
   433  						Eventually(session).Should(Say("Uploading buildpack %s as %s\\.\\.\\.", buildpackName, username))
   434  						Eventually(session).Should(Say("Done uploading"))
   435  						Eventually(session).Should(Say("OK"))
   436  						Eventually(session).Should(Exit(0))
   437  					})
   438  
   439  					session := helpers.CF("buildpacks")
   440  					Eventually(session).Should(Say(`%s\s+3`, buildpackName))
   441  					Eventually(session).Should(Exit(0))
   442  				})
   443  			})
   444  		})
   445  
   446  		When("using the enable/disable flags", func() {
   447  			When("specifying disable flag", func() {
   448  				It("disables buildpack", func() {
   449  					helpers.BuildpackWithoutStack(func(buildpackPath string) {
   450  						session := helpers.CF("create-buildpack", buildpackName, buildpackPath, "1", "--disable")
   451  						Eventually(session).Should(Say("Creating buildpack %s as %s\\.\\.\\.", buildpackName, username))
   452  						Eventually(session).Should(Say("OK"))
   453  						Eventually(session).Should(Say("Uploading buildpack %s as %s\\.\\.\\.", buildpackName, username))
   454  						Eventually(session).Should(Say("Done uploading"))
   455  						Eventually(session).Should(Say("OK"))
   456  						Eventually(session).Should(Exit(0))
   457  					})
   458  
   459  					session := helpers.CF("buildpacks")
   460  					Eventually(session).Should(Say(`%s\s+1\s+false`, buildpackName))
   461  					Eventually(session).Should(Exit(0))
   462  				})
   463  			})
   464  
   465  			When("specifying both enable and disable flags", func() {
   466  				It("returns the appropriate error", func() {
   467  					helpers.BuildpackWithoutStack(func(buildpackPath string) {
   468  						session := helpers.CF("create-buildpack", buildpackName, buildpackPath, "1", "--enable", "--disable")
   469  						Eventually(session).Should(Say("FAILED"))
   470  						Eventually(session.Err).Should(Say("Incorrect Usage: The following arguments cannot be used together: --enable, --disable"))
   471  						Eventually(session).Should(Exit(1))
   472  					})
   473  				})
   474  			})
   475  		})
   476  	})
   477  })