github.com/arunkumar7540/cli@v6.45.0+incompatible/integration/v6/experimental/v3_push_command_test.go (about)

     1  package experimental
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"os"
     8  	"regexp"
     9  
    10  	"code.cloudfoundry.org/cli/integration/helpers"
    11  	. "github.com/onsi/ginkgo"
    12  	. "github.com/onsi/gomega"
    13  	. "github.com/onsi/gomega/gbytes"
    14  	. "github.com/onsi/gomega/gexec"
    15  )
    16  
    17  var _ = Describe("v3-push command", func() {
    18  	var (
    19  		orgName           string
    20  		spaceName         string
    21  		appName           string
    22  		userName          string
    23  		PublicDockerImage = "cloudfoundry/diego-docker-app-custom"
    24  	)
    25  
    26  	BeforeEach(func() {
    27  		orgName = helpers.NewOrgName()
    28  		spaceName = helpers.NewSpaceName()
    29  		appName = helpers.PrefixedRandomName("app")
    30  		userName, _ = helpers.GetCredentials()
    31  		helpers.TurnOffExperimental()
    32  	})
    33  
    34  	AfterEach(func() {
    35  		helpers.TurnOnExperimental()
    36  	})
    37  
    38  	Describe("help", func() {
    39  		When("--help flag is set", func() {
    40  			It("Displays command usage to output", func() {
    41  				session := helpers.CF("v3-push", "--help")
    42  				Eventually(session).Should(Say("NAME:"))
    43  				Eventually(session).Should(Say("v3-push - Push a new app or sync changes to an existing app"))
    44  				Eventually(session).Should(Say("USAGE:"))
    45  				Eventually(session).Should(Say("cf v3-push APP_NAME \\[-b BUILDPACK\\]\\.\\.\\. \\[-p APP_PATH\\] \\[--no-route\\]"))
    46  				Eventually(session).Should(Say("cf v3-push APP_NAME --docker-image \\[REGISTRY_HOST:PORT/\\]IMAGE\\[:TAG\\] \\[--docker-username USERNAME\\] \\[--no-route\\]"))
    47  				Eventually(session).Should(Say("OPTIONS:"))
    48  				Eventually(session).Should(Say("-b\\s+Custom buildpack by name \\(e\\.g\\. my-buildpack\\) or Git URL \\(e\\.g\\. 'https://github.com/cloudfoundry/java-buildpack.git'\\) or Git URL with a branch or tag \\(e\\.g\\. 'https://github.com/cloudfoundry/java-buildpack\\.git#v3.3.0' for 'v3.3.0' tag\\)\\. To use built-in buildpacks only, specify 'default' or 'null'"))
    49  				Eventually(session).Should(Say("--docker-image, -o\\s+Docker image to use \\(e\\.g\\. user/docker-image-name\\)"))
    50  				Eventually(session).Should(Say("--docker-username\\s+Repository username; used with password from environment variable CF_DOCKER_PASSWORD"))
    51  				Eventually(session).Should(Say("--no-route\\s+Do not map a route to this app"))
    52  				Eventually(session).Should(Say("-p\\s+Path to app directory or to a zip file of the contents of the app directory"))
    53  				Eventually(session).Should(Say("ENVIRONMENT:"))
    54  				Eventually(session).Should(Say("CF_DOCKER_PASSWORD=\\s+Password used for private docker repository"))
    55  				Eventually(session).Should(Say("CF_STAGING_TIMEOUT=15\\s+Max wait time for buildpack staging, in minutes"))
    56  				Eventually(session).Should(Say("CF_STARTUP_TIMEOUT=5\\s+Max wait time for app instance startup, in minutes"))
    57  
    58  				Eventually(session).Should(Exit(0))
    59  			})
    60  		})
    61  	})
    62  
    63  	When("the app name is not provided", func() {
    64  		It("tells the user that the app name is required, prints help text, and exits 1", func() {
    65  			session := helpers.CF("v3-push")
    66  
    67  			Eventually(session.Err).Should(Say("Incorrect Usage: the required argument `APP_NAME` was not provided"))
    68  			Eventually(session).Should(Say("NAME:"))
    69  			Eventually(session).Should(Exit(1))
    70  		})
    71  	})
    72  
    73  	It("displays the experimental warning", func() {
    74  		session := helpers.CF("v3-push", appName)
    75  		Eventually(session.Err).Should(Say("This command is in EXPERIMENTAL stage and may change without notice"))
    76  		Eventually(session).Should(Exit())
    77  	})
    78  
    79  	When("the -b flag is not given an arg", func() {
    80  		It("tells the user that the flag requires an arg, prints help text, and exits 1", func() {
    81  			session := helpers.CF("v3-push", appName, "-b")
    82  
    83  			Eventually(session.Err).Should(Say("Incorrect Usage: expected argument for flag `-b'"))
    84  			Eventually(session).Should(Say("NAME:"))
    85  			Eventually(session).Should(Exit(1))
    86  		})
    87  	})
    88  
    89  	When("the -p flag is not given an arg", func() {
    90  		It("tells the user that the flag requires an arg, prints help text, and exits 1", func() {
    91  			session := helpers.CF("v3-push", appName, "-p")
    92  
    93  			Eventually(session.Err).Should(Say("Incorrect Usage: expected argument for flag `-p'"))
    94  			Eventually(session).Should(Say("NAME:"))
    95  			Eventually(session).Should(Exit(1))
    96  		})
    97  	})
    98  
    99  	When("the -p flag path does not exist", func() {
   100  		It("tells the user that the flag requires an arg, prints help text, and exits 1", func() {
   101  			session := helpers.CF("v3-push", appName, "-p", "path/that/does/not/exist")
   102  
   103  			Eventually(session.Err).Should(Say("Incorrect Usage: The specified path 'path/that/does/not/exist' does not exist."))
   104  			Eventually(session).Should(Say("NAME:"))
   105  			Eventually(session).Should(Exit(1))
   106  		})
   107  	})
   108  
   109  	When("the environment is not setup correctly", func() {
   110  		When("no API endpoint is set", func() {
   111  			BeforeEach(func() {
   112  				helpers.UnsetAPI()
   113  			})
   114  
   115  			It("fails with no API endpoint set message", func() {
   116  				session := helpers.CF("v3-push", appName)
   117  				Eventually(session).Should(Say("FAILED"))
   118  				Eventually(session.Err).Should(Say("No API endpoint set\\. Use 'cf login' or 'cf api' to target an endpoint\\."))
   119  				Eventually(session).Should(Exit(1))
   120  			})
   121  		})
   122  
   123  		When("not logged in", func() {
   124  			BeforeEach(func() {
   125  				helpers.LogoutCF()
   126  			})
   127  
   128  			It("fails with not logged in message", func() {
   129  				session := helpers.CF("v3-push", appName)
   130  				Eventually(session).Should(Say("FAILED"))
   131  				Eventually(session.Err).Should(Say("Not logged in\\. Use 'cf login' to log in\\."))
   132  				Eventually(session).Should(Exit(1))
   133  			})
   134  		})
   135  
   136  		When("there is no org set", func() {
   137  			BeforeEach(func() {
   138  				helpers.LogoutCF()
   139  				helpers.LoginCF()
   140  			})
   141  
   142  			It("fails with no org targeted error message", func() {
   143  				session := helpers.CF("v3-push", appName)
   144  				Eventually(session).Should(Say("FAILED"))
   145  				Eventually(session.Err).Should(Say("No org targeted, use 'cf target -o ORG' to target an org\\."))
   146  				Eventually(session).Should(Exit(1))
   147  			})
   148  		})
   149  
   150  		When("there is no space set", func() {
   151  			BeforeEach(func() {
   152  				helpers.LogoutCF()
   153  				helpers.LoginCF()
   154  				helpers.TargetOrg(ReadOnlyOrg)
   155  			})
   156  
   157  			It("fails with no space targeted error message", func() {
   158  				session := helpers.CF("v3-push", appName)
   159  				Eventually(session).Should(Say("FAILED"))
   160  				Eventually(session.Err).Should(Say("No space targeted, use 'cf target -s SPACE' to target a space\\."))
   161  				Eventually(session).Should(Exit(1))
   162  			})
   163  		})
   164  	})
   165  
   166  	When("the environment is set up correctly", func() {
   167  		var domainName string
   168  
   169  		BeforeEach(func() {
   170  			helpers.SetupCF(orgName, spaceName)
   171  			domainName = helpers.DefaultSharedDomain()
   172  		})
   173  
   174  		AfterEach(func() {
   175  			helpers.QuickDeleteOrg(orgName)
   176  		})
   177  
   178  		When("the app exists", func() {
   179  			var session *Session
   180  			BeforeEach(func() {
   181  				helpers.WithHelloWorldApp(func(appDir string) {
   182  					Eventually(helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName)).Should(Exit(0))
   183  				})
   184  
   185  				helpers.WithHelloWorldApp(func(appDir string) {
   186  					session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName, "-b", "https://github.com/cloudfoundry/staticfile-buildpack")
   187  					Eventually(session).Should(Exit(0))
   188  				})
   189  			})
   190  
   191  			It("pushes the app", func() {
   192  				Eventually(session).Should(Say("Updating app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   193  				Eventually(session).Should(Say("OK"))
   194  				Eventually(session).Should(Say(""))
   195  				Eventually(session).Should(Say("Uploading and creating bits package for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   196  				Eventually(session).Should(Say("OK"))
   197  				Eventually(session).Should(Say(""))
   198  				Eventually(session).Should(Say("Stopping app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   199  				Eventually(session).Should(Say("OK"))
   200  				Eventually(session).Should(Say(""))
   201  				Eventually(session).Should(Say("Staging package for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   202  				Eventually(session).Should(Say("OK"))
   203  				Eventually(session).Should(Say("Setting app %s to droplet .+ in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   204  				Eventually(session).Should(Say("OK"))
   205  				Eventually(session).Should(Say(""))
   206  				Eventually(session).Should(Say("Mapping routes\\.\\.\\."))
   207  				Eventually(session).Should(Say("OK"))
   208  				Eventually(session).Should(Say(""))
   209  				Eventually(session).Should(Say("Starting app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   210  				Eventually(session).Should(Say("OK"))
   211  				Eventually(session).Should(Say(""))
   212  				Eventually(session).Should(Say("Waiting for app to start\\.\\.\\."))
   213  				Eventually(session).Should(Say("Showing health and status for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   214  				Eventually(session).Should(Say(""))
   215  				Eventually(session).Should(Say("name:\\s+%s", appName))
   216  				Eventually(session).Should(Say("requested state:\\s+started"))
   217  				Eventually(session).Should(Say("routes:\\s+%s\\.%s", appName, domainName))
   218  				Eventually(session).Should(Say("stack:\\s+cflinuxfs"))
   219  
   220  				// TODO: Uncomment when capi sorts out droplet buildpack name/detectoutput
   221  				// Eventually(session).Should(Say("buildpacks:\\s+https://github.com/cloudfoundry/staticfile-buildpack"))
   222  				Eventually(session).Should(Say(""))
   223  				Eventually(session).Should(Say("type:\\s+web"))
   224  				Eventually(session).Should(Say("instances:\\s+1/1"))
   225  				Eventually(session).Should(Say("memory usage:\\s+\\d+(M|G)"))
   226  				Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`))
   227  				Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M"))
   228  			})
   229  		})
   230  
   231  		When("the app does not already exist", func() {
   232  			var session *Session
   233  
   234  			BeforeEach(func() {
   235  				helpers.WithHelloWorldApp(func(appDir string) {
   236  					session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName)
   237  					Eventually(session).Should(Exit(0))
   238  				})
   239  			})
   240  
   241  			It("pushes the app", func() {
   242  				Eventually(session).Should(Say("Creating app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   243  				Eventually(session).Should(Say("OK"))
   244  				Eventually(session).Should(Say(""))
   245  				Eventually(session).Should(Say("Uploading and creating bits package for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   246  				Eventually(session).Should(Say("OK"))
   247  				Eventually(session).Should(Say(""))
   248  				Consistently(session).ShouldNot(Say("Stopping app %s", appName))
   249  				Eventually(session).Should(Say("Staging package for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   250  				Eventually(session).Should(Say("OK"))
   251  				Eventually(session).Should(Say("Setting app %s to droplet .+ in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   252  				Eventually(session).Should(Say("OK"))
   253  				Eventually(session).Should(Say(""))
   254  				Eventually(session).Should(Say("Mapping routes\\.\\.\\."))
   255  				Eventually(session).Should(Say("OK"))
   256  				Eventually(session).Should(Say(""))
   257  				Eventually(session).Should(Say("Starting app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   258  				Eventually(session).Should(Say("OK"))
   259  				Eventually(session).Should(Say(""))
   260  				Eventually(session).Should(Say("Waiting for app to start\\.\\.\\."))
   261  				Eventually(session).Should(Say("Showing health and status for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   262  				Eventually(session).Should(Say(""))
   263  				Eventually(session).Should(Say("name:\\s+%s", appName))
   264  				Eventually(session).Should(Say("requested state:\\s+started"))
   265  				Eventually(session).Should(Say("routes:\\s+%s\\.%s", appName, domainName))
   266  				Eventually(session).Should(Say("stack:\\s+cflinuxfs"))
   267  				Eventually(session).Should(Say("buildpacks:\\s+staticfile"))
   268  				Eventually(session).Should(Say(""))
   269  				Eventually(session).Should(Say("type:\\s+web"))
   270  				Eventually(session).Should(Say("instances:\\s+1/1"))
   271  				Eventually(session).Should(Say("memory usage:\\s+\\d+(M|G)"))
   272  				Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`))
   273  				Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M"))
   274  			})
   275  		})
   276  
   277  		When("the app crashes", func() {
   278  			var session *Session
   279  
   280  			BeforeEach(func() {
   281  				helpers.WithCrashingApp(func(appDir string) {
   282  					session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName)
   283  					Eventually(session).Should(Exit(0))
   284  				})
   285  			})
   286  
   287  			It("pushes the app", func() {
   288  				Eventually(session).Should(Say("Creating app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   289  				Eventually(session).Should(Say("OK"))
   290  				Eventually(session).Should(Say(""))
   291  				Eventually(session).Should(Say("Uploading and creating bits package for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   292  				Eventually(session).Should(Say("OK"))
   293  				Eventually(session).Should(Say(""))
   294  				Consistently(session).ShouldNot(Say("Stopping app %s", appName))
   295  				Eventually(session).Should(Say("Staging package for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   296  				Eventually(session).Should(Say("OK"))
   297  				Eventually(session).Should(Say("Setting app %s to droplet .+ in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   298  				Eventually(session).Should(Say("OK"))
   299  				Eventually(session).Should(Say(""))
   300  				Eventually(session).Should(Say("Mapping routes\\.\\.\\."))
   301  				Eventually(session).Should(Say("OK"))
   302  				Eventually(session).Should(Say(""))
   303  				Eventually(session).Should(Say("Starting app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   304  				Eventually(session).Should(Say("OK"))
   305  				Eventually(session).Should(Say(""))
   306  				Eventually(session).Should(Say("Waiting for app to start\\.\\.\\."))
   307  				Eventually(session).Should(Say("Showing health and status for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   308  				Eventually(session).Should(Say(""))
   309  				Eventually(session).Should(Say("name:\\s+%s", appName))
   310  				Eventually(session).Should(Say("requested state:\\s+started"))
   311  				Eventually(session).Should(Say("routes:\\s+%s\\.%s", appName, domainName))
   312  				Eventually(session).Should(Say("stack:\\s+cflinuxfs"))
   313  				Eventually(session).Should(Say("buildpacks:\\s+ruby"))
   314  				Eventually(session).Should(Say(""))
   315  				Eventually(session).Should(Say("type:\\s+web"))
   316  				Eventually(session).Should(Say("instances:\\s+0/1"))
   317  				Eventually(session).Should(Say("memory usage:\\s+\\d+(M|G)"))
   318  				Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`))
   319  				Eventually(session).Should(Say("#0\\s+crashed\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M"))
   320  			})
   321  		})
   322  
   323  		When("the -p flag is provided", func() {
   324  			When("the path is a directory", func() {
   325  				When("the directory contains files", func() {
   326  					It("pushes the app from the directory", func() {
   327  						helpers.WithHelloWorldApp(func(appDir string) {
   328  							session := helpers.CF("v3-push", appName, "-p", appDir)
   329  
   330  							Eventually(session).Should(Say("Starting app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   331  							Eventually(session).Should(Say("Waiting for app to start\\.\\.\\."))
   332  							Eventually(session).Should(Say("Showing health and status for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   333  							Eventually(session).Should(Say(""))
   334  							Eventually(session).Should(Say("name:\\s+%s", appName))
   335  							Eventually(session).Should(Say("requested state:\\s+started"))
   336  							Eventually(session).Should(Say("routes:\\s+%s\\.%s", appName, domainName))
   337  							Eventually(session).Should(Say("stack:\\s+cflinuxfs"))
   338  							Eventually(session).Should(Say("buildpacks:\\s+staticfile"))
   339  							Eventually(session).Should(Say(""))
   340  							Eventually(session).Should(Say("type:\\s+web"))
   341  							Eventually(session).Should(Say("instances:\\s+1/1"))
   342  							Eventually(session).Should(Say("memory usage:\\s+\\d+(M|G)"))
   343  							Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`))
   344  							Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M"))
   345  
   346  							Eventually(session).Should(Exit(0))
   347  						})
   348  					})
   349  				})
   350  
   351  				When("the directory is empty", func() {
   352  					var emptyDir string
   353  
   354  					BeforeEach(func() {
   355  						var err error
   356  						emptyDir, err = ioutil.TempDir("", "integration-push-path-empty")
   357  						Expect(err).ToNot(HaveOccurred())
   358  					})
   359  
   360  					AfterEach(func() {
   361  						Expect(os.RemoveAll(emptyDir)).ToNot(HaveOccurred())
   362  					})
   363  
   364  					It("returns an error", func() {
   365  						session := helpers.CF("v3-push", appName, "-p", emptyDir)
   366  						Eventually(session.Err).Should(Say("No app files found in '%s'", regexp.QuoteMeta(emptyDir)))
   367  						Eventually(session).Should(Exit(1))
   368  					})
   369  				})
   370  			})
   371  
   372  			When("the path is a zip file", func() {
   373  				Context("pushing a zip file", func() {
   374  					var archive string
   375  
   376  					BeforeEach(func() {
   377  						helpers.WithHelloWorldApp(func(appDir string) {
   378  							tmpfile, err := ioutil.TempFile("", "push-archive-integration")
   379  							Expect(err).ToNot(HaveOccurred())
   380  							archive = tmpfile.Name()
   381  							Expect(tmpfile.Close())
   382  
   383  							err = helpers.Zipit(appDir, archive, "")
   384  							Expect(err).ToNot(HaveOccurred())
   385  						})
   386  					})
   387  
   388  					AfterEach(func() {
   389  						Expect(os.RemoveAll(archive)).ToNot(HaveOccurred())
   390  					})
   391  
   392  					It("pushes the app from the zip file", func() {
   393  						session := helpers.CF("v3-push", appName, "-p", archive)
   394  
   395  						Eventually(session).Should(Say("Starting app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   396  						Eventually(session).Should(Say("Waiting for app to start\\.\\.\\."))
   397  						Eventually(session).Should(Say("Showing health and status for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   398  						Eventually(session).Should(Say(""))
   399  						Eventually(session).Should(Say("name:\\s+%s", appName))
   400  						Eventually(session).Should(Say("requested state:\\s+started"))
   401  						Eventually(session).Should(Say("routes:\\s+%s\\.%s", appName, domainName))
   402  						Eventually(session).Should(Say("stack:\\s+cflinuxfs"))
   403  						Eventually(session).Should(Say("buildpacks:\\s+staticfile"))
   404  						Eventually(session).Should(Say(""))
   405  						Eventually(session).Should(Say("type:\\s+web"))
   406  						Eventually(session).Should(Say("instances:\\s+1/1"))
   407  						Eventually(session).Should(Say("memory usage:\\s+\\d+(M|G)"))
   408  						Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`))
   409  						Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M"))
   410  
   411  						Eventually(session).Should(Exit(0))
   412  					})
   413  				})
   414  			})
   415  
   416  			When("the path is a symlink to a directory", func() {
   417  				var symlinkPath string
   418  
   419  				BeforeEach(func() {
   420  					tempFile, err := ioutil.TempFile("", "symlink-")
   421  					Expect(err).ToNot(HaveOccurred())
   422  					Expect(tempFile.Close()).To(Succeed())
   423  
   424  					symlinkPath = tempFile.Name()
   425  					Expect(os.Remove(symlinkPath)).To(Succeed())
   426  				})
   427  
   428  				AfterEach(func() {
   429  					Expect(os.Remove(symlinkPath)).To(Succeed())
   430  				})
   431  
   432  				It("creates and uploads the package from the directory", func() {
   433  					helpers.WithHelloWorldApp(func(appDir string) {
   434  						Expect(os.Symlink(appDir, symlinkPath)).To(Succeed())
   435  
   436  						session := helpers.CF("v3-push", appName, "-p", symlinkPath)
   437  
   438  						Eventually(session).Should(Say("Starting app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   439  						Eventually(session).Should(Say("Waiting for app to start\\.\\.\\."))
   440  						Eventually(session).Should(Say("Showing health and status for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   441  						Eventually(session).Should(Say(""))
   442  						Eventually(session).Should(Say("name:\\s+%s", appName))
   443  						Eventually(session).Should(Say("requested state:\\s+started"))
   444  						Eventually(session).Should(Say("routes:\\s+%s\\.%s", appName, domainName))
   445  						Eventually(session).Should(Say("stack:\\s+cflinuxfs"))
   446  						Eventually(session).Should(Say("buildpacks:\\s+staticfile"))
   447  						Eventually(session).Should(Say(""))
   448  						Eventually(session).Should(Say("type:\\s+web"))
   449  						Eventually(session).Should(Say("instances:\\s+1/1"))
   450  						Eventually(session).Should(Say("memory usage:\\s+\\d+(M|G)"))
   451  						Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`))
   452  						Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M"))
   453  
   454  						Eventually(session).Should(Exit(0))
   455  					})
   456  				})
   457  			})
   458  
   459  			When("the path is a symlink to a zip file", func() {
   460  				var (
   461  					archive     string
   462  					symlinkPath string
   463  				)
   464  
   465  				BeforeEach(func() {
   466  					helpers.WithHelloWorldApp(func(appDir string) {
   467  						tmpfile, err := ioutil.TempFile("", "package-archive-integration")
   468  						Expect(err).ToNot(HaveOccurred())
   469  						archive = tmpfile.Name()
   470  						Expect(tmpfile.Close())
   471  
   472  						err = helpers.Zipit(appDir, archive, "")
   473  						Expect(err).ToNot(HaveOccurred())
   474  					})
   475  
   476  					tempFile, err := ioutil.TempFile("", "symlink-to-archive-")
   477  					Expect(err).ToNot(HaveOccurred())
   478  					Expect(tempFile.Close()).To(Succeed())
   479  
   480  					symlinkPath = tempFile.Name()
   481  					Expect(os.Remove(symlinkPath)).To(Succeed())
   482  					Expect(os.Symlink(archive, symlinkPath)).To(Succeed())
   483  				})
   484  
   485  				AfterEach(func() {
   486  					Expect(os.Remove(archive)).To(Succeed())
   487  					Expect(os.Remove(symlinkPath)).To(Succeed())
   488  				})
   489  
   490  				It("creates and uploads the package from the zip file", func() {
   491  					session := helpers.CF("v3-push", appName, "-p", symlinkPath)
   492  
   493  					Eventually(session).Should(Say("Starting app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   494  					Eventually(session).Should(Say("Waiting for app to start\\.\\.\\."))
   495  					Eventually(session).Should(Say("Showing health and status for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName))
   496  					Eventually(session).Should(Say(""))
   497  					Eventually(session).Should(Say("name:\\s+%s", appName))
   498  					Eventually(session).Should(Say("requested state:\\s+started"))
   499  					Eventually(session).Should(Say("routes:\\s+%s\\.%s", appName, domainName))
   500  					Eventually(session).Should(Say("stack:\\s+cflinuxfs"))
   501  					Eventually(session).Should(Say("buildpacks:\\s+staticfile"))
   502  					Eventually(session).Should(Say(""))
   503  					Eventually(session).Should(Say("type:\\s+web"))
   504  					Eventually(session).Should(Say("instances:\\s+1/1"))
   505  					Eventually(session).Should(Say("memory usage:\\s+\\d+(M|G)"))
   506  					Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`))
   507  					Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M"))
   508  
   509  					Eventually(session).Should(Exit(0))
   510  				})
   511  			})
   512  		})
   513  
   514  		When("the --no-route flag is set", func() {
   515  			var session *Session
   516  
   517  			BeforeEach(func() {
   518  				helpers.WithHelloWorldApp(func(appDir string) {
   519  					session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName, "--no-route")
   520  					Eventually(session).Should(Exit(0))
   521  				})
   522  			})
   523  
   524  			It("does not map any routes to the app", func() {
   525  				Consistently(session).ShouldNot(Say("Mapping routes\\.\\.\\."))
   526  				Eventually(session).Should(Say("name:\\s+%s", appName))
   527  				Eventually(session).Should(Say("requested state:\\s+started"))
   528  				Eventually(session).Should(Say("routes:\\s+\n"))
   529  				Eventually(session).Should(Say("stack:\\s+cflinuxfs"))
   530  				Eventually(session).Should(Say("buildpacks:\\s+staticfile"))
   531  				Eventually(session).Should(Say(""))
   532  				Eventually(session).Should(Say("type:\\s+web"))
   533  				Eventually(session).Should(Say("instances:\\s+1/1"))
   534  				Eventually(session).Should(Say("memory usage:\\s+\\d+(M|G)"))
   535  				Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`))
   536  				Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M"))
   537  			})
   538  		})
   539  
   540  		When("the -b flag is set", func() {
   541  			var session *Session
   542  
   543  			When("pushing a multi-buildpack app", func() {
   544  				BeforeEach(func() {
   545  					helpers.WithMultiBuildpackApp(func(appDir string) {
   546  						session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName, "-b", "ruby_buildpack", "-b", "go_buildpack")
   547  
   548  						// TODO: uncomment this expectation once capi-release displays all buildpacks on droplet
   549  						// Story: https://www.pivotaltracker.com/story/show/150425459
   550  						// Eventually(session).Should(Say("buildpacks:.*ruby_buildpack, go_buildpack"))
   551  
   552  						Eventually(session).Should(Exit(0))
   553  					})
   554  				})
   555  
   556  				It("successfully compiles and runs the app", func() {
   557  					resp, err := http.Get(fmt.Sprintf("http://%s.%s", appName, helpers.DefaultSharedDomain()))
   558  					Expect(err).ToNot(HaveOccurred())
   559  					Expect(resp.StatusCode).To(Equal(http.StatusOK))
   560  				})
   561  			})
   562  
   563  			When("resetting the buildpack to default", func() {
   564  				BeforeEach(func() {
   565  					helpers.WithHelloWorldApp(func(appDir string) {
   566  						Eventually(helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName, "-b", "java_buildpack")).Should(Exit(1))
   567  						session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName, "-b", "default")
   568  						Eventually(session).Should(Exit(0))
   569  					})
   570  				})
   571  
   572  				It("successfully pushes the app", func() {
   573  					Eventually(session).Should(Say("name:\\s+%s", appName))
   574  					Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`))
   575  					Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M"))
   576  				})
   577  			})
   578  
   579  			When("omitting the buildpack", func() {
   580  				BeforeEach(func() {
   581  					helpers.WithHelloWorldApp(func(appDir string) {
   582  						Eventually(helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName, "-b", "java_buildpack")).Should(Exit(1))
   583  						session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName)
   584  						Eventually(session).Should(Exit(1))
   585  					})
   586  				})
   587  
   588  				It("continues using previously set buildpack", func() {
   589  					Eventually(session).Should(Say("FAILED"))
   590  				})
   591  			})
   592  
   593  			When("the buildpack is invalid", func() {
   594  				BeforeEach(func() {
   595  					helpers.WithHelloWorldApp(func(appDir string) {
   596  						session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName, "-b", "wut")
   597  						Eventually(session).Should(Exit(1))
   598  					})
   599  				})
   600  
   601  				It("errors and does not push the app", func() {
   602  					Consistently(session).ShouldNot(Say("Creating app"))
   603  					Eventually(session).Should(Say("FAILED"))
   604  					Eventually(session.Err).Should(Say(`Buildpack "wut" must be an existing admin buildpack or a valid git URI`))
   605  				})
   606  			})
   607  
   608  			When("the buildpack is valid", func() {
   609  				BeforeEach(func() {
   610  					helpers.WithHelloWorldApp(func(appDir string) {
   611  						session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName, "-b", "https://github.com/cloudfoundry/staticfile-buildpack")
   612  						Eventually(session).Should(Exit(0))
   613  					})
   614  				})
   615  
   616  				It("uses the specified buildpack", func() {
   617  					Eventually(session).Should(Say("name:\\s+%s", appName))
   618  					Eventually(session).Should(Say("requested state:\\s+started"))
   619  					Eventually(session).Should(Say("routes:\\s+%s\\.%s", appName, domainName))
   620  					Eventually(session).Should(Say("stack:\\s+cflinuxfs"))
   621  
   622  					// TODO: Uncomment when capi sorts out droplet buildpack name/detectoutput
   623  					// Eventually(session).Should(Say("buildpacks:\\s+https://github.com/cloudfoundry/staticfile-buildpack"))
   624  					Eventually(session).Should(Say(""))
   625  					Eventually(session).Should(Say("type:\\s+web"))
   626  					Eventually(session).Should(Say("instances:\\s+1/1"))
   627  					Eventually(session).Should(Say("memory usage:\\s+\\d+(M|G)"))
   628  					Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`))
   629  					Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M"))
   630  				})
   631  			})
   632  		})
   633  
   634  		When("the -o flag is set", func() {
   635  			When("the docker image is valid", func() {
   636  				It("uses the specified docker image", func() {
   637  					session := helpers.CF("v3-push", appName, "-o", PublicDockerImage)
   638  
   639  					Eventually(session).Should(Say("name:\\s+%s", appName))
   640  					Eventually(session).Should(Say("requested state:\\s+started"))
   641  					Eventually(session).Should(Say("routes:\\s+%s\\.%s", appName, domainName))
   642  					Eventually(session).Should(Say("stack:"))
   643  					Eventually(session).ShouldNot(Say("buildpacks:"))
   644  					Eventually(session).Should(Say("docker image:\\s+%s", PublicDockerImage))
   645  					Eventually(session).Should(Say(""))
   646  					Eventually(session).Should(Say("type:\\s+web"))
   647  					Eventually(session).Should(Say("instances:\\s+1/1"))
   648  					Eventually(session).Should(Say("memory usage:\\s+\\d+(M|G)"))
   649  					Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`))
   650  					Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M"))
   651  					Eventually(session).Should(Exit(0))
   652  				})
   653  			})
   654  
   655  			When("the docker image is invalid", func() {
   656  				It("displays an error and exits 1", func() {
   657  					session := helpers.CF("v3-push", appName, "-o", "some-invalid-docker-image")
   658  					Eventually(session).Should(Say("FAILED"))
   659  					Eventually(session.Err).Should(Say("StagingError - Staging error: staging failed"))
   660  					Eventually(session).Should(Exit(1))
   661  				})
   662  			})
   663  
   664  			When("a docker username and password are provided with a private image", func() {
   665  				var (
   666  					privateDockerImage    string
   667  					privateDockerUsername string
   668  					privateDockerPassword string
   669  				)
   670  
   671  				BeforeEach(func() {
   672  					privateDockerImage = os.Getenv("CF_INT_DOCKER_IMAGE")
   673  					privateDockerUsername = os.Getenv("CF_INT_DOCKER_USERNAME")
   674  					privateDockerPassword = os.Getenv("CF_INT_DOCKER_PASSWORD")
   675  
   676  					if privateDockerImage == "" || privateDockerUsername == "" || privateDockerPassword == "" {
   677  						Skip("CF_INT_DOCKER_IMAGE, CF_INT_DOCKER_USERNAME, or CF_INT_DOCKER_PASSWORD is not set")
   678  					}
   679  				})
   680  
   681  				It("uses the specified private docker image", func() {
   682  					session := helpers.CustomCF(
   683  						helpers.CFEnv{
   684  							EnvVars: map[string]string{"CF_DOCKER_PASSWORD": privateDockerPassword},
   685  						},
   686  						"v3-push", "--docker-username", privateDockerUsername, "--docker-image", privateDockerImage, appName,
   687  					)
   688  
   689  					Eventually(session).Should(Say("name:\\s+%s", appName))
   690  					Eventually(session).Should(Say("requested state:\\s+started"))
   691  					Eventually(session).Should(Say("routes:\\s+%s\\.%s", appName, domainName))
   692  					Eventually(session).Should(Say("stack:"))
   693  					Eventually(session).ShouldNot(Say("buildpacks:"))
   694  					Eventually(session).Should(Say("docker image:\\s+%s", privateDockerImage))
   695  					Eventually(session).Should(Say(""))
   696  					Eventually(session).Should(Say("type:\\s+web"))
   697  					Eventually(session).Should(Say("instances:\\s+1/1"))
   698  					Eventually(session).Should(Say("memory usage:\\s+\\d+(M|G)"))
   699  					Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`))
   700  					Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M"))
   701  					Eventually(session).Should(Exit(0))
   702  				})
   703  			})
   704  		})
   705  
   706  		Describe("argument combination errors", func() {
   707  			When("the --docker-username is provided without the -o flag", func() {
   708  				It("displays an error and exits 1", func() {
   709  					helpers.WithHelloWorldApp(func(appDir string) {
   710  						session := helpers.CF("v3-push", appName, "--docker-username", "some-username")
   711  						Eventually(session).Should(Say("FAILED"))
   712  						Eventually(session.Err).Should(Say("Incorrect Usage: '--docker-image, -o' and '--docker-username' must be used together."))
   713  						Eventually(session).Should(Say("NAME:"))
   714  						Eventually(session).Should(Exit(1))
   715  					})
   716  				})
   717  			})
   718  
   719  			When("the --docker-username and -p flags are provided together", func() {
   720  				It("displays an error and exits 1", func() {
   721  					helpers.WithHelloWorldApp(func(appDir string) {
   722  						session := helpers.CF("v3-push", appName, "--docker-username", "some-username", "-p", appDir)
   723  						Eventually(session).Should(Say("FAILED"))
   724  						Eventually(session.Err).Should(Say("Incorrect Usage: '--docker-image, -o' and '--docker-username' must be used together."))
   725  						Eventually(session).Should(Say("NAME:"))
   726  						Eventually(session).Should(Exit(1))
   727  					})
   728  				})
   729  			})
   730  
   731  			When("the --docker-username is provided without a password", func() {
   732  				var oldPassword string
   733  
   734  				BeforeEach(func() {
   735  					oldPassword = os.Getenv("CF_DOCKER_PASSWORD")
   736  					err := os.Unsetenv("CF_DOCKER_PASSWORD")
   737  					Expect(err).ToNot(HaveOccurred())
   738  				})
   739  
   740  				AfterEach(func() {
   741  					err := os.Setenv("CF_DOCKER_PASSWORD", oldPassword)
   742  					Expect(err).ToNot(HaveOccurred())
   743  				})
   744  
   745  				It("displays an error and exits 1", func() {
   746  					helpers.WithHelloWorldApp(func(appDir string) {
   747  						session := helpers.CF("v3-push", appName, "--docker-username", "some-username", "--docker-image", "some-image")
   748  						Eventually(session).Should(Say("FAILED"))
   749  						Eventually(session.Err).Should(Say("Environment variable CF_DOCKER_PASSWORD not set\\."))
   750  						Eventually(session).Should(Exit(1))
   751  					})
   752  				})
   753  			})
   754  
   755  			When("the -o and -p flags are provided together", func() {
   756  				It("displays an error and exits 1", func() {
   757  					helpers.WithHelloWorldApp(func(appDir string) {
   758  						session := helpers.CF("v3-push", appName, "-o", PublicDockerImage, "-p", appDir)
   759  						Eventually(session).Should(Say("FAILED"))
   760  						Eventually(session.Err).Should(Say("Incorrect Usage: The following arguments cannot be used together: --docker-image, -o, -p"))
   761  						Eventually(session).Should(Say("NAME:"))
   762  						Eventually(session).Should(Exit(1))
   763  					})
   764  				})
   765  			})
   766  
   767  			When("the -o and -b flags are provided together", func() {
   768  				It("displays an error and exits 1", func() {
   769  					helpers.WithHelloWorldApp(func(appDir string) {
   770  						session := helpers.CF("v3-push", appName, "-o", PublicDockerImage, "-b", "some-buildpack")
   771  						Eventually(session).Should(Say("FAILED"))
   772  						Eventually(session.Err).Should(Say("Incorrect Usage: The following arguments cannot be used together: -b, --docker-image, -o"))
   773  						Eventually(session).Should(Say("NAME:"))
   774  						Eventually(session).Should(Exit(1))
   775  					})
   776  				})
   777  			})
   778  		})
   779  	})
   780  })