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