github.com/arunkumar7540/cli@v6.45.0+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+cflinuxfs`)) 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+cflinuxfs`)) 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+cflinuxfs`)) 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+cflinuxfs`)) 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+cflinuxfs`)) 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+cflinuxfs`)) 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+cflinuxfs`)) 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+cflinuxfs`)) 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", "cflinuxfs3") 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+cflinuxfs3`)) 519 }) 520 }) 521 522 When("a non-default stack is specified", func() { 523 It("uses the specified stack", func() { 524 525 Skip("we have only one stack") 526 527 }) 528 }) 529 530 When("the both -s and -b are specified", func() { 531 When("the buildpack and stack both exist", func() { 532 When("the buildpack specified exists for the stack specified", func() { 533 It("creates the app with the specified stack and buildpack", func() { 534 var session *Session 535 helpers.WithHelloWorldApp(func(appDir string) { 536 session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-zdt-push", appName, "-b", "https://github.com/cloudfoundry/staticfile-buildpack", "-s", "cflinuxfs3") 537 Eventually(session).Should(Exit(0)) 538 }) 539 // TODO: assert specific error text when it is written 540 }) 541 }) 542 543 When("the buildpack specified does not exist for the stack specified", func() { 544 It("prints the appropriate error", func() { 545 var session *Session 546 helpers.WithHelloWorldApp(func(appDir string) { 547 session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-zdt-push", appName, "-b", "ruby_buildpack", "-s", "windows2012R2") 548 Eventually(session).Should(Exit(1)) 549 }) 550 // TODO: assert specific error text when it is written 551 }) 552 }) 553 }) 554 }) 555 556 When("the specified stack does not exist", func() { 557 It("errors", func() { 558 var session *Session 559 helpers.WithHelloWorldApp(func(appDir string) { 560 session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-zdt-push", appName, "-s", "invalid_stack") 561 Eventually(session).Should(Exit(1)) 562 }) 563 Eventually(session).Should(Say("FAILED")) 564 // TODO: confirm the text of the error message 565 Eventually(session.Err).Should(Say(`Stack must be an existing stack`)) 566 }) 567 }) 568 }) 569 570 Context("when the -b flag is set", func() { 571 var session *Session 572 573 Context("when pushing a multi-buildpack app", func() { 574 BeforeEach(func() { 575 helpers.WithMultiBuildpackApp(func(appDir string) { 576 session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-zdt-push", appName, "-b", "ruby_buildpack", "-b", "go_buildpack") 577 578 // TODO: uncomment this expectation once capi-release displays all buildpacks on droplet 579 // Story: https://www.pivotaltracker.com/story/show/150425459 580 // Eventually(session).Should(Say("buildpacks:.*ruby_buildpack, go_buildpack")) 581 582 Eventually(session).Should(Exit(0)) 583 }) 584 }) 585 586 It("successfully compiles and runs the app", func() { 587 resp, err := http.Get(fmt.Sprintf("http://%s.%s", appName, helpers.DefaultSharedDomain())) 588 Expect(err).ToNot(HaveOccurred()) 589 Expect(resp.StatusCode).To(Equal(http.StatusOK)) 590 }) 591 }) 592 593 Context("when resetting the buildpack to default", func() { 594 BeforeEach(func() { 595 helpers.WithHelloWorldApp(func(appDir string) { 596 Eventually(helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-zdt-push", appName, "-b", "java_buildpack")).Should(Exit(1)) 597 session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-zdt-push", appName, "-b", "default") 598 Eventually(session).Should(Exit(0)) 599 }) 600 }) 601 602 It("successfully pushes the app", func() { 603 Eventually(session).Should(Say(`name:\s+%s`, appName)) 604 Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`)) 605 Eventually(session).Should(Say(`#0\s+running\s+\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [AP]M`)) 606 }) 607 }) 608 609 Context("when omitting the buildpack", func() { 610 BeforeEach(func() { 611 helpers.WithHelloWorldApp(func(appDir string) { 612 Eventually(helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-zdt-push", appName, "-b", "java_buildpack")).Should(Exit(1)) 613 session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-zdt-push", appName) 614 Eventually(session).Should(Exit(1)) 615 }) 616 }) 617 618 It("continues using previously set buildpack", func() { 619 Eventually(session).Should(Say("FAILED")) 620 }) 621 }) 622 623 Context("when the buildpack is invalid", func() { 624 BeforeEach(func() { 625 helpers.WithHelloWorldApp(func(appDir string) { 626 session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-zdt-push", appName, "-b", "wut") 627 Eventually(session).Should(Exit(1)) 628 }) 629 }) 630 631 It("errors and does not push the app", func() { 632 Consistently(session).ShouldNot(Say("Creating app")) 633 Eventually(session).Should(Say("FAILED")) 634 Eventually(session.Err).Should(Say(`Buildpack "wut" must be an existing admin buildpack or a valid git URI`)) 635 }) 636 }) 637 638 Context("when the buildpack is valid", func() { 639 BeforeEach(func() { 640 helpers.WithHelloWorldApp(func(appDir string) { 641 session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-zdt-push", appName, "-b", "https://github.com/cloudfoundry/staticfile-buildpack") 642 Eventually(session).Should(Exit(0)) 643 }) 644 }) 645 646 It("uses the specified buildpack", func() { 647 Eventually(session).Should(Say(`name:\s+%s`, appName)) 648 Eventually(session).Should(Say(`requested state:\s+started`)) 649 Eventually(session).Should(Say(`routes:\s+%s\.%s`, appName, domainName)) 650 Eventually(session).Should(Say(`stack:\s+cflinuxfs`)) 651 652 // TODO: Uncomment when capi sorts out droplet buildpack name/detectoutput 653 // Eventually(session).Should(Say(`buildpacks:\s+https://github.com/cloudfoundry/staticfile-buildpack`)) 654 Eventually(session).Should(Say("")) 655 Eventually(session).Should(Say(`type:\s+web`)) 656 Eventually(session).Should(Say(`instances:\s+1/1`)) 657 Eventually(session).Should(Say(`memory usage:\s+\d+(M|G)`)) 658 Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`)) 659 Eventually(session).Should(Say(`#0\s+running\s+\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [AP]M`)) 660 }) 661 }) 662 }) 663 664 Context("when the -o flag is set", func() { 665 Context("when the docker image is valid", func() { 666 It("uses the specified docker image", func() { 667 session := helpers.CF("v3-zdt-push", appName, "-o", PublicDockerImage) 668 669 Eventually(session).Should(Say(`name:\s+%s`, appName)) 670 Eventually(session).Should(Say(`requested state:\s+started`)) 671 Eventually(session).Should(Say(`routes:\s+%s\.%s`, appName, domainName)) 672 Eventually(session).Should(Say("stack:")) 673 Eventually(session).ShouldNot(Say("buildpacks:")) 674 Eventually(session).Should(Say(`docker image:\s+%s`, PublicDockerImage)) 675 Eventually(session).Should(Say("")) 676 Eventually(session).Should(Say(`type:\s+web`)) 677 Eventually(session).Should(Say(`instances:\s+1/1`)) 678 Eventually(session).Should(Say(`memory usage:\s+\d+(M|G)`)) 679 Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`)) 680 Eventually(session).Should(Say(`#0\s+running\s+\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [AP]M`)) 681 Eventually(session).Should(Exit(0)) 682 }) 683 }) 684 685 Context("when the docker image is invalid", func() { 686 It("displays an error and exits 1", func() { 687 session := helpers.CF("v3-zdt-push", appName, "-o", "some-invalid-docker-image") 688 Eventually(session).Should(Say("FAILED")) 689 Eventually(session.Err).Should(Say("StagingError - Staging error: staging failed")) 690 Eventually(session).Should(Exit(1)) 691 }) 692 }) 693 694 Context("when a docker username and password are provided with a private image", func() { 695 var ( 696 privateDockerImage string 697 privateDockerUsername string 698 privateDockerPassword string 699 ) 700 701 BeforeEach(func() { 702 privateDockerImage = os.Getenv("CF_INT_DOCKER_IMAGE") 703 privateDockerUsername = os.Getenv("CF_INT_DOCKER_USERNAME") 704 privateDockerPassword = os.Getenv("CF_INT_DOCKER_PASSWORD") 705 706 if privateDockerImage == "" || privateDockerUsername == "" || privateDockerPassword == "" { 707 Skip("CF_INT_DOCKER_IMAGE, CF_INT_DOCKER_USERNAME, or CF_INT_DOCKER_PASSWORD is not set") 708 } 709 }) 710 711 It("uses the specified private docker image", func() { 712 session := helpers.CustomCF( 713 helpers.CFEnv{ 714 EnvVars: map[string]string{"CF_DOCKER_PASSWORD": privateDockerPassword}, 715 }, 716 "v3-zdt-push", "--docker-username", privateDockerUsername, "--docker-image", privateDockerImage, appName, 717 ) 718 719 Eventually(session).Should(Say(`name:\s+%s`, appName)) 720 Eventually(session).Should(Say(`requested state:\s+started`)) 721 Eventually(session).Should(Say(`routes:\s+%s\.%s`, appName, domainName)) 722 Eventually(session).Should(Say("stack:")) 723 Eventually(session).ShouldNot(Say("buildpacks:")) 724 Eventually(session).Should(Say(`docker image:\s+%s`, privateDockerImage)) 725 Eventually(session).Should(Say("")) 726 Eventually(session).Should(Say(`type:\s+web`)) 727 Eventually(session).Should(Say(`instances:\s+1/1`)) 728 Eventually(session).Should(Say(`memory usage:\s+\d+(M|G)`)) 729 Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`)) 730 Eventually(session).Should(Say(`#0\s+running\s+\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [AP]M`)) 731 Eventually(session).Should(Exit(0)) 732 }) 733 }) 734 }) 735 736 Describe("argument combination errors", func() { 737 Context("when the --docker-username is provided without the -o flag", func() { 738 It("displays an error and exits 1", func() { 739 helpers.WithHelloWorldApp(func(appDir string) { 740 session := helpers.CF("v3-zdt-push", appName, "--docker-username", "some-username") 741 Eventually(session).Should(Say("FAILED")) 742 Eventually(session.Err).Should(Say("Incorrect Usage: '--docker-image, -o' and '--docker-username' must be used together.")) 743 Eventually(session).Should(Say("NAME:")) 744 Eventually(session).Should(Exit(1)) 745 }) 746 }) 747 }) 748 749 Context("when the --docker-username and -p flags are provided together", func() { 750 It("displays an error and exits 1", func() { 751 helpers.WithHelloWorldApp(func(appDir string) { 752 session := helpers.CF("v3-zdt-push", appName, "--docker-username", "some-username", "-p", appDir) 753 Eventually(session).Should(Say("FAILED")) 754 Eventually(session.Err).Should(Say("Incorrect Usage: '--docker-image, -o' and '--docker-username' must be used together.")) 755 Eventually(session).Should(Say("NAME:")) 756 Eventually(session).Should(Exit(1)) 757 }) 758 }) 759 }) 760 761 Context("when the --docker-username is provided without a password", func() { 762 var oldPassword string 763 764 BeforeEach(func() { 765 oldPassword = os.Getenv("CF_DOCKER_PASSWORD") 766 err := os.Unsetenv("CF_DOCKER_PASSWORD") 767 Expect(err).ToNot(HaveOccurred()) 768 }) 769 770 AfterEach(func() { 771 err := os.Setenv("CF_DOCKER_PASSWORD", oldPassword) 772 Expect(err).ToNot(HaveOccurred()) 773 }) 774 775 It("displays an error and exits 1", func() { 776 helpers.WithHelloWorldApp(func(appDir string) { 777 session := helpers.CF("v3-zdt-push", appName, "--docker-username", "some-username", "--docker-image", "some-image") 778 Eventually(session).Should(Say("FAILED")) 779 Eventually(session.Err).Should(Say(`Environment variable CF_DOCKER_PASSWORD not set\.`)) 780 Eventually(session).Should(Exit(1)) 781 }) 782 }) 783 }) 784 785 Context("when the -o and -p flags are provided together", func() { 786 It("displays an error and exits 1", func() { 787 helpers.WithHelloWorldApp(func(appDir string) { 788 session := helpers.CF("v3-zdt-push", appName, "-o", PublicDockerImage, "-p", appDir) 789 Eventually(session).Should(Say("FAILED")) 790 Eventually(session.Err).Should(Say("Incorrect Usage: The following arguments cannot be used together: --docker-image, -o, -p")) 791 Eventually(session).Should(Say("NAME:")) 792 Eventually(session).Should(Exit(1)) 793 }) 794 }) 795 }) 796 797 Context("when the -o and -b flags are provided together", func() { 798 It("displays an error and exits 1", func() { 799 helpers.WithHelloWorldApp(func(appDir string) { 800 session := helpers.CF("v3-zdt-push", appName, "-o", PublicDockerImage, "-b", "some-buildpack") 801 Eventually(session).Should(Say("FAILED")) 802 Eventually(session.Err).Should(Say("Incorrect Usage: The following arguments cannot be used together: -b, --docker-image, -o")) 803 Eventually(session).Should(Say("NAME:")) 804 Eventually(session).Should(Exit(1)) 805 }) 806 }) 807 }) 808 }) 809 }) 810 })