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