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 })