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