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