github.com/nimakaviani/cli@v6.37.1-0.20180619223813-e734901a73fa+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.Err).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.StartAndTargetServerWithAPIVersions(helpers.DefaultV2Version, "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 helpers.SetupCF(orgName, spaceName) 205 domainName = helpers.DefaultSharedDomain() 206 }) 207 208 AfterEach(func() { 209 helpers.QuickDeleteOrg(orgName) 210 }) 211 212 Context("when the app exists", func() { 213 var session *Session 214 BeforeEach(func() { 215 helpers.WithHelloWorldApp(func(appDir string) { 216 Eventually(helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName)).Should(Exit(0)) 217 }) 218 219 helpers.WithHelloWorldApp(func(appDir string) { 220 session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName, "-b", "https://github.com/cloudfoundry/staticfile-buildpack") 221 Eventually(session).Should(Exit(0)) 222 }) 223 }) 224 225 It("pushes the app", func() { 226 Eventually(session).Should(Say("Updating app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 227 Eventually(session).Should(Say("OK")) 228 Eventually(session).Should(Say("")) 229 Eventually(session).Should(Say("Uploading and creating bits package for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 230 Eventually(session).Should(Say("OK")) 231 Eventually(session).Should(Say("")) 232 Eventually(session).Should(Say("Stopping app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 233 Eventually(session).Should(Say("OK")) 234 Eventually(session).Should(Say("")) 235 Eventually(session).Should(Say("Staging package for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 236 Eventually(session).Should(Say("OK")) 237 Eventually(session).Should(Say("Setting app %s to droplet .+ in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 238 Eventually(session).Should(Say("OK")) 239 Eventually(session).Should(Say("")) 240 Eventually(session).Should(Say("Mapping routes\\.\\.\\.")) 241 Eventually(session).Should(Say("OK")) 242 Eventually(session).Should(Say("")) 243 Eventually(session).Should(Say("Starting app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 244 Eventually(session).Should(Say("OK")) 245 Eventually(session).Should(Say("")) 246 Eventually(session).Should(Say("Waiting for app to start\\.\\.\\.")) 247 Eventually(session).Should(Say("Showing health and status for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 248 Eventually(session).Should(Say("")) 249 Eventually(session).Should(Say("name:\\s+%s", appName)) 250 Eventually(session).Should(Say("requested state:\\s+started")) 251 Eventually(session).Should(Say("processes:\\s+web:1/1")) 252 Eventually(session).Should(Say("memory usage:\\s+\\d+M x 1")) 253 Eventually(session).Should(Say("routes:\\s+%s\\.%s", appName, domainName)) 254 Eventually(session).Should(Say("stack:\\s+cflinuxfs2")) 255 256 // TODO: Uncomment when capi sorts out droplet buildpack name/detectoutput 257 // Eventually(session).Should(Say("buildpacks:\\s+https://github.com/cloudfoundry/staticfile-buildpack")) 258 Eventually(session).Should(Say("")) 259 Eventually(session).Should(Say("web:1/1")) 260 Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`)) 261 Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M")) 262 }) 263 }) 264 265 Context("when the app does not already exist", func() { 266 var session *Session 267 268 BeforeEach(func() { 269 helpers.WithHelloWorldApp(func(appDir string) { 270 session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName) 271 Eventually(session).Should(Exit(0)) 272 }) 273 }) 274 275 It("pushes the app", func() { 276 Eventually(session).Should(Say("Creating app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 277 Eventually(session).Should(Say("OK")) 278 Eventually(session).Should(Say("")) 279 Eventually(session).Should(Say("Uploading and creating bits package for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 280 Eventually(session).Should(Say("OK")) 281 Eventually(session).Should(Say("")) 282 Consistently(session).ShouldNot(Say("Stopping app %s", appName)) 283 Eventually(session).Should(Say("Staging package for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 284 Eventually(session).Should(Say("OK")) 285 Eventually(session).Should(Say("Setting app %s to droplet .+ in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 286 Eventually(session).Should(Say("OK")) 287 Eventually(session).Should(Say("")) 288 Eventually(session).Should(Say("Mapping routes\\.\\.\\.")) 289 Eventually(session).Should(Say("OK")) 290 Eventually(session).Should(Say("")) 291 Eventually(session).Should(Say("Starting app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 292 Eventually(session).Should(Say("OK")) 293 Eventually(session).Should(Say("")) 294 Eventually(session).Should(Say("Waiting for app to start\\.\\.\\.")) 295 Eventually(session).Should(Say("Showing health and status for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 296 Eventually(session).Should(Say("")) 297 Eventually(session).Should(Say("name:\\s+%s", appName)) 298 Eventually(session).Should(Say("requested state:\\s+started")) 299 Eventually(session).Should(Say("processes:\\s+web:1/1")) 300 Eventually(session).Should(Say("memory usage:\\s+\\d+M x 1")) 301 Eventually(session).Should(Say("routes:\\s+%s\\.%s", appName, domainName)) 302 Eventually(session).Should(Say("stack:\\s+cflinuxfs2")) 303 Eventually(session).Should(Say("buildpacks:\\s+staticfile")) 304 Eventually(session).Should(Say("")) 305 Eventually(session).Should(Say("web:1/1")) 306 Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`)) 307 Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M")) 308 }) 309 }) 310 311 Context("when the app crashes", func() { 312 var session *Session 313 314 BeforeEach(func() { 315 helpers.WithCrashingApp(func(appDir string) { 316 session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName) 317 Eventually(session).Should(Exit(0)) 318 }) 319 }) 320 321 It("pushes the app", func() { 322 Eventually(session).Should(Say("Creating app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 323 Eventually(session).Should(Say("OK")) 324 Eventually(session).Should(Say("")) 325 Eventually(session).Should(Say("Uploading and creating bits package for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 326 Eventually(session).Should(Say("OK")) 327 Eventually(session).Should(Say("")) 328 Consistently(session).ShouldNot(Say("Stopping app %s", appName)) 329 Eventually(session).Should(Say("Staging package for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 330 Eventually(session).Should(Say("OK")) 331 Eventually(session).Should(Say("Setting app %s to droplet .+ in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 332 Eventually(session).Should(Say("OK")) 333 Eventually(session).Should(Say("")) 334 Eventually(session).Should(Say("Mapping routes\\.\\.\\.")) 335 Eventually(session).Should(Say("OK")) 336 Eventually(session).Should(Say("")) 337 Eventually(session).Should(Say("Starting app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 338 Eventually(session).Should(Say("OK")) 339 Eventually(session).Should(Say("")) 340 Eventually(session).Should(Say("Waiting for app to start\\.\\.\\.")) 341 Eventually(session).Should(Say("Showing health and status for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 342 Eventually(session).Should(Say("")) 343 Eventually(session).Should(Say("name:\\s+%s", appName)) 344 Eventually(session).Should(Say("requested state:\\s+started")) 345 Eventually(session).Should(Say("processes:\\s+web:0/1")) 346 Eventually(session).Should(Say("memory usage:\\s+\\d+M x 1")) 347 Eventually(session).Should(Say("routes:\\s+%s\\.%s", appName, domainName)) 348 Eventually(session).Should(Say("stack:\\s+cflinuxfs2")) 349 Eventually(session).Should(Say("buildpacks:\\s+ruby")) 350 Eventually(session).Should(Say("")) 351 Eventually(session).Should(Say("web:0/1")) 352 Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`)) 353 Eventually(session).Should(Say("#0\\s+crashed\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M")) 354 }) 355 }) 356 357 Context("when the -p flag is provided", func() { 358 Context("when the path is a directory", func() { 359 Context("when the directory contains files", func() { 360 It("pushes the app from the directory", func() { 361 helpers.WithHelloWorldApp(func(appDir string) { 362 session := helpers.CF("v3-push", appName, "-p", appDir) 363 364 Eventually(session).Should(Say("Starting app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 365 Eventually(session).Should(Say("Waiting for app to start\\.\\.\\.")) 366 Eventually(session).Should(Say("Showing health and status for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 367 Eventually(session).Should(Say("")) 368 Eventually(session).Should(Say("name:\\s+%s", appName)) 369 Eventually(session).Should(Say("requested state:\\s+started")) 370 Eventually(session).Should(Say("processes:\\s+web:1/1")) 371 Eventually(session).Should(Say("memory usage:\\s+\\d+M x 1")) 372 Eventually(session).Should(Say("routes:\\s+%s\\.%s", appName, domainName)) 373 Eventually(session).Should(Say("stack:\\s+cflinuxfs2")) 374 Eventually(session).Should(Say("buildpacks:\\s+staticfile")) 375 Eventually(session).Should(Say("")) 376 Eventually(session).Should(Say("web:1/1")) 377 Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`)) 378 Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M")) 379 380 Eventually(session).Should(Exit(0)) 381 }) 382 }) 383 }) 384 385 Context("when the directory is empty", func() { 386 var emptyDir string 387 388 BeforeEach(func() { 389 var err error 390 emptyDir, err = ioutil.TempDir("", "integration-push-path-empty") 391 Expect(err).ToNot(HaveOccurred()) 392 }) 393 394 AfterEach(func() { 395 Expect(os.RemoveAll(emptyDir)).ToNot(HaveOccurred()) 396 }) 397 398 It("returns an error", func() { 399 session := helpers.CF("v3-push", appName, "-p", emptyDir) 400 Eventually(session.Err).Should(Say("No app files found in '%s'", regexp.QuoteMeta(emptyDir))) 401 Eventually(session).Should(Exit(1)) 402 }) 403 }) 404 }) 405 406 Context("when the path is a zip file", func() { 407 Context("pushing a zip file", func() { 408 var archive string 409 410 BeforeEach(func() { 411 helpers.WithHelloWorldApp(func(appDir string) { 412 tmpfile, err := ioutil.TempFile("", "push-archive-integration") 413 Expect(err).ToNot(HaveOccurred()) 414 archive = tmpfile.Name() 415 Expect(tmpfile.Close()) 416 417 err = helpers.Zipit(appDir, archive, "") 418 Expect(err).ToNot(HaveOccurred()) 419 }) 420 }) 421 422 AfterEach(func() { 423 Expect(os.RemoveAll(archive)).ToNot(HaveOccurred()) 424 }) 425 426 It("pushes the app from the zip file", func() { 427 session := helpers.CF("v3-push", appName, "-p", archive) 428 429 Eventually(session).Should(Say("Starting app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 430 Eventually(session).Should(Say("Waiting for app to start\\.\\.\\.")) 431 Eventually(session).Should(Say("Showing health and status for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 432 Eventually(session).Should(Say("")) 433 Eventually(session).Should(Say("name:\\s+%s", appName)) 434 Eventually(session).Should(Say("requested state:\\s+started")) 435 Eventually(session).Should(Say("processes:\\s+web:1/1")) 436 Eventually(session).Should(Say("memory usage:\\s+\\d+M x 1")) 437 Eventually(session).Should(Say("routes:\\s+%s\\.%s", appName, domainName)) 438 Eventually(session).Should(Say("stack:\\s+cflinuxfs2")) 439 Eventually(session).Should(Say("buildpacks:\\s+staticfile")) 440 Eventually(session).Should(Say("")) 441 Eventually(session).Should(Say("web:1/1")) 442 Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`)) 443 Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M")) 444 445 Eventually(session).Should(Exit(0)) 446 }) 447 }) 448 }) 449 450 Context("when the path is a symlink to a directory", func() { 451 var symlinkPath string 452 453 BeforeEach(func() { 454 tempFile, err := ioutil.TempFile("", "symlink-") 455 Expect(err).ToNot(HaveOccurred()) 456 Expect(tempFile.Close()).To(Succeed()) 457 458 symlinkPath = tempFile.Name() 459 Expect(os.Remove(symlinkPath)).To(Succeed()) 460 }) 461 462 AfterEach(func() { 463 Expect(os.Remove(symlinkPath)).To(Succeed()) 464 }) 465 466 It("creates and uploads the package from the directory", func() { 467 helpers.WithHelloWorldApp(func(appDir string) { 468 Expect(os.Symlink(appDir, symlinkPath)).To(Succeed()) 469 470 session := helpers.CF("v3-push", appName, "-p", symlinkPath) 471 472 Eventually(session).Should(Say("Starting app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 473 Eventually(session).Should(Say("Waiting for app to start\\.\\.\\.")) 474 Eventually(session).Should(Say("Showing health and status for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 475 Eventually(session).Should(Say("")) 476 Eventually(session).Should(Say("name:\\s+%s", appName)) 477 Eventually(session).Should(Say("requested state:\\s+started")) 478 Eventually(session).Should(Say("processes:\\s+web:1/1")) 479 Eventually(session).Should(Say("memory usage:\\s+\\d+M x 1")) 480 Eventually(session).Should(Say("routes:\\s+%s\\.%s", appName, domainName)) 481 Eventually(session).Should(Say("stack:\\s+cflinuxfs2")) 482 Eventually(session).Should(Say("buildpacks:\\s+staticfile")) 483 Eventually(session).Should(Say("")) 484 Eventually(session).Should(Say("web:1/1")) 485 Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`)) 486 Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M")) 487 488 Eventually(session).Should(Exit(0)) 489 }) 490 }) 491 }) 492 493 Context("when the path is a symlink to a zip file", func() { 494 var ( 495 archive string 496 symlinkPath string 497 ) 498 499 BeforeEach(func() { 500 helpers.WithHelloWorldApp(func(appDir string) { 501 tmpfile, err := ioutil.TempFile("", "package-archive-integration") 502 Expect(err).ToNot(HaveOccurred()) 503 archive = tmpfile.Name() 504 Expect(tmpfile.Close()) 505 506 err = helpers.Zipit(appDir, archive, "") 507 Expect(err).ToNot(HaveOccurred()) 508 }) 509 510 tempFile, err := ioutil.TempFile("", "symlink-to-archive-") 511 Expect(err).ToNot(HaveOccurred()) 512 Expect(tempFile.Close()).To(Succeed()) 513 514 symlinkPath = tempFile.Name() 515 Expect(os.Remove(symlinkPath)).To(Succeed()) 516 Expect(os.Symlink(archive, symlinkPath)).To(Succeed()) 517 }) 518 519 AfterEach(func() { 520 Expect(os.Remove(archive)).To(Succeed()) 521 Expect(os.Remove(symlinkPath)).To(Succeed()) 522 }) 523 524 It("creates and uploads the package from the zip file", func() { 525 session := helpers.CF("v3-push", appName, "-p", symlinkPath) 526 527 Eventually(session).Should(Say("Starting app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 528 Eventually(session).Should(Say("Waiting for app to start\\.\\.\\.")) 529 Eventually(session).Should(Say("Showing health and status for app %s in org %s / space %s as %s\\.\\.\\.", appName, orgName, spaceName, userName)) 530 Eventually(session).Should(Say("")) 531 Eventually(session).Should(Say("name:\\s+%s", appName)) 532 Eventually(session).Should(Say("requested state:\\s+started")) 533 Eventually(session).Should(Say("processes:\\s+web:1/1")) 534 Eventually(session).Should(Say("memory usage:\\s+\\d+M x 1")) 535 Eventually(session).Should(Say("routes:\\s+%s\\.%s", appName, domainName)) 536 Eventually(session).Should(Say("stack:\\s+cflinuxfs2")) 537 Eventually(session).Should(Say("buildpacks:\\s+staticfile")) 538 Eventually(session).Should(Say("")) 539 Eventually(session).Should(Say("web:1/1")) 540 Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`)) 541 Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M")) 542 543 Eventually(session).Should(Exit(0)) 544 }) 545 }) 546 }) 547 548 Context("when the --no-route flag is set", func() { 549 var session *Session 550 551 BeforeEach(func() { 552 helpers.WithHelloWorldApp(func(appDir string) { 553 session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName, "--no-route") 554 Eventually(session).Should(Exit(0)) 555 }) 556 }) 557 558 It("does not map any routes to the app", func() { 559 Consistently(session).ShouldNot(Say("Mapping routes\\.\\.\\.")) 560 Eventually(session).Should(Say("name:\\s+%s", appName)) 561 Eventually(session).Should(Say("requested state:\\s+started")) 562 Eventually(session).Should(Say("processes:\\s+web:1/1")) 563 Eventually(session).Should(Say("memory usage:\\s+\\d+M x 1")) 564 Eventually(session).Should(Say("routes:\\s+\n")) 565 Eventually(session).Should(Say("stack:\\s+cflinuxfs2")) 566 Eventually(session).Should(Say("buildpacks:\\s+staticfile")) 567 Eventually(session).Should(Say("")) 568 Eventually(session).Should(Say("web:1/1")) 569 Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`)) 570 Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M")) 571 }) 572 }) 573 574 Context("when the -b flag is set", func() { 575 var session *Session 576 577 Context("when pushing a multi-buildpack app", func() { 578 BeforeEach(func() { 579 helpers.WithMultiBuildpackApp(func(appDir string) { 580 session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName, "-b", "ruby_buildpack", "-b", "go_buildpack") 581 582 // TODO: uncomment this expectation once capi-release displays all buildpacks on droplet 583 // Story: https://www.pivotaltracker.com/story/show/150425459 584 // Eventually(session).Should(Say("buildpacks:.*ruby_buildpack, go_buildpack")) 585 586 Eventually(session).Should(Exit(0)) 587 }) 588 }) 589 590 It("successfully compiles and runs the app", func() { 591 resp, err := http.Get(fmt.Sprintf("http://%s.%s", appName, helpers.DefaultSharedDomain())) 592 Expect(err).ToNot(HaveOccurred()) 593 Expect(resp.StatusCode).To(Equal(http.StatusOK)) 594 }) 595 }) 596 597 Context("when resetting the buildpack to default", func() { 598 BeforeEach(func() { 599 helpers.WithHelloWorldApp(func(appDir string) { 600 Eventually(helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName, "-b", "java_buildpack")).Should(Exit(1)) 601 session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName, "-b", "default") 602 Eventually(session).Should(Exit(0)) 603 }) 604 }) 605 606 It("successfully pushes the app", func() { 607 Eventually(session).Should(Say("name:\\s+%s", appName)) 608 Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`)) 609 Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M")) 610 }) 611 }) 612 613 Context("when omitting the buildpack", func() { 614 BeforeEach(func() { 615 helpers.WithHelloWorldApp(func(appDir string) { 616 Eventually(helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName, "-b", "java_buildpack")).Should(Exit(1)) 617 session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName) 618 Eventually(session).Should(Exit(1)) 619 }) 620 }) 621 622 It("continues using previously set buildpack", func() { 623 Eventually(session).Should(Say("FAILED")) 624 }) 625 }) 626 627 Context("when the buildpack is invalid", func() { 628 BeforeEach(func() { 629 helpers.WithHelloWorldApp(func(appDir string) { 630 session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName, "-b", "wut") 631 Eventually(session).Should(Exit(1)) 632 }) 633 }) 634 635 It("errors and does not push the app", func() { 636 Consistently(session).ShouldNot(Say("Creating app")) 637 Eventually(session).Should(Say("FAILED")) 638 Eventually(session.Err).Should(Say(`Buildpack "wut" must be an existing admin buildpack or a valid git URI`)) 639 }) 640 }) 641 642 Context("when the buildpack is valid", func() { 643 BeforeEach(func() { 644 helpers.WithHelloWorldApp(func(appDir string) { 645 session = helpers.CustomCF(helpers.CFEnv{WorkingDirectory: appDir}, "v3-push", appName, "-b", "https://github.com/cloudfoundry/staticfile-buildpack") 646 Eventually(session).Should(Exit(0)) 647 }) 648 }) 649 650 It("uses the specified buildpack", func() { 651 Eventually(session).Should(Say("name:\\s+%s", appName)) 652 Eventually(session).Should(Say("requested state:\\s+started")) 653 Eventually(session).Should(Say("processes:\\s+web:1/1")) 654 Eventually(session).Should(Say("memory usage:\\s+\\d+M x 1")) 655 Eventually(session).Should(Say("routes:\\s+%s\\.%s", appName, domainName)) 656 Eventually(session).Should(Say("stack:\\s+cflinuxfs2")) 657 658 // TODO: Uncomment when capi sorts out droplet buildpack name/detectoutput 659 // Eventually(session).Should(Say("buildpacks:\\s+https://github.com/cloudfoundry/staticfile-buildpack")) 660 Eventually(session).Should(Say("")) 661 Eventually(session).Should(Say("web:1/1")) 662 Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`)) 663 Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M")) 664 }) 665 }) 666 }) 667 668 Context("when the -o flag is set", func() { 669 Context("when the docker image is valid", func() { 670 It("uses the specified docker image", func() { 671 session := helpers.CF("v3-push", appName, "-o", PublicDockerImage) 672 673 Eventually(session).Should(Say("name:\\s+%s", appName)) 674 Eventually(session).Should(Say("requested state:\\s+started")) 675 Eventually(session).Should(Say("processes:\\s+web:1/1")) 676 Eventually(session).Should(Say("memory usage:\\s+\\d+M x 1")) 677 Eventually(session).Should(Say("routes:\\s+%s\\.%s", appName, domainName)) 678 Eventually(session).Should(Say("stack:")) 679 Eventually(session).ShouldNot(Say("buildpacks:")) 680 Eventually(session).Should(Say("docker image:\\s+%s", PublicDockerImage)) 681 Eventually(session).Should(Say("")) 682 Eventually(session).Should(Say("web:1/1")) 683 Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`)) 684 Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M")) 685 Eventually(session).Should(Exit(0)) 686 }) 687 }) 688 689 Context("when the docker image is invalid", func() { 690 It("displays an error and exits 1", func() { 691 session := helpers.CF("v3-push", appName, "-o", "some-invalid-docker-image") 692 Eventually(session).Should(Say("FAILED")) 693 Eventually(session.Err).Should(Say("StagingError - Staging error: staging failed")) 694 Eventually(session).Should(Exit(1)) 695 }) 696 }) 697 698 Context("when a docker username and password are provided with a private image", func() { 699 var ( 700 privateDockerImage string 701 privateDockerUsername string 702 privateDockerPassword string 703 ) 704 705 BeforeEach(func() { 706 privateDockerImage = os.Getenv("CF_INT_DOCKER_IMAGE") 707 privateDockerUsername = os.Getenv("CF_INT_DOCKER_USERNAME") 708 privateDockerPassword = os.Getenv("CF_INT_DOCKER_PASSWORD") 709 710 if privateDockerImage == "" || privateDockerUsername == "" || privateDockerPassword == "" { 711 Skip("CF_INT_DOCKER_IMAGE, CF_INT_DOCKER_USERNAME, or CF_INT_DOCKER_PASSWORD is not set") 712 } 713 }) 714 715 It("uses the specified private docker image", func() { 716 session := helpers.CustomCF( 717 helpers.CFEnv{ 718 EnvVars: map[string]string{"CF_DOCKER_PASSWORD": privateDockerPassword}, 719 }, 720 "v3-push", "--docker-username", privateDockerUsername, "--docker-image", privateDockerImage, appName, 721 ) 722 723 Eventually(session).Should(Say("name:\\s+%s", appName)) 724 Eventually(session).Should(Say("requested state:\\s+started")) 725 Eventually(session).Should(Say("processes:\\s+web:1/1")) 726 Eventually(session).Should(Say("memory usage:\\s+\\d+M x 1")) 727 Eventually(session).Should(Say("routes:\\s+%s\\.%s", appName, domainName)) 728 Eventually(session).Should(Say("stack:")) 729 Eventually(session).ShouldNot(Say("buildpacks:")) 730 Eventually(session).Should(Say("docker image:\\s+%s", privateDockerImage)) 731 Eventually(session).Should(Say("")) 732 Eventually(session).Should(Say("web:1/1")) 733 Eventually(session).Should(Say(`state\s+since\s+cpu\s+memory\s+disk`)) 734 Eventually(session).Should(Say("#0\\s+running\\s+\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M")) 735 Eventually(session).Should(Exit(0)) 736 }) 737 }) 738 }) 739 740 Describe("argument combination errors", func() { 741 Context("when the --docker-username is provided without the -o flag", func() { 742 It("displays an error and exits 1", func() { 743 helpers.WithHelloWorldApp(func(appDir string) { 744 session := helpers.CF("v3-push", appName, "--docker-username", "some-username") 745 Eventually(session).Should(Say("FAILED")) 746 Eventually(session.Err).Should(Say("Incorrect Usage: '--docker-image, -o' and '--docker-username' must be used together.")) 747 Eventually(session).Should(Say("NAME:")) 748 Eventually(session).Should(Exit(1)) 749 }) 750 }) 751 }) 752 753 Context("when the --docker-username and -p flags are provided together", func() { 754 It("displays an error and exits 1", func() { 755 helpers.WithHelloWorldApp(func(appDir string) { 756 session := helpers.CF("v3-push", appName, "--docker-username", "some-username", "-p", appDir) 757 Eventually(session).Should(Say("FAILED")) 758 Eventually(session.Err).Should(Say("Incorrect Usage: '--docker-image, -o' and '--docker-username' must be used together.")) 759 Eventually(session).Should(Say("NAME:")) 760 Eventually(session).Should(Exit(1)) 761 }) 762 }) 763 }) 764 765 Context("when the --docker-username is provided without a password", func() { 766 var oldPassword string 767 768 BeforeEach(func() { 769 oldPassword = os.Getenv("CF_DOCKER_PASSWORD") 770 err := os.Unsetenv("CF_DOCKER_PASSWORD") 771 Expect(err).ToNot(HaveOccurred()) 772 }) 773 774 AfterEach(func() { 775 err := os.Setenv("CF_DOCKER_PASSWORD", oldPassword) 776 Expect(err).ToNot(HaveOccurred()) 777 }) 778 779 It("displays an error and exits 1", func() { 780 helpers.WithHelloWorldApp(func(appDir string) { 781 session := helpers.CF("v3-push", appName, "--docker-username", "some-username", "--docker-image", "some-image") 782 Eventually(session).Should(Say("FAILED")) 783 Eventually(session.Err).Should(Say("Environment variable CF_DOCKER_PASSWORD not set\\.")) 784 Eventually(session).Should(Exit(1)) 785 }) 786 }) 787 }) 788 789 Context("when the -o and -p flags are provided together", func() { 790 It("displays an error and exits 1", func() { 791 helpers.WithHelloWorldApp(func(appDir string) { 792 session := helpers.CF("v3-push", appName, "-o", PublicDockerImage, "-p", appDir) 793 Eventually(session).Should(Say("FAILED")) 794 Eventually(session.Err).Should(Say("Incorrect Usage: The following arguments cannot be used together: --docker-image, -o, -p")) 795 Eventually(session).Should(Say("NAME:")) 796 Eventually(session).Should(Exit(1)) 797 }) 798 }) 799 }) 800 801 Context("when the -o and -b flags are provided together", func() { 802 It("displays an error and exits 1", func() { 803 helpers.WithHelloWorldApp(func(appDir string) { 804 session := helpers.CF("v3-push", appName, "-o", PublicDockerImage, "-b", "some-buildpack") 805 Eventually(session).Should(Say("FAILED")) 806 Eventually(session.Err).Should(Say("Incorrect Usage: The following arguments cannot be used together: -b, --docker-image, -o")) 807 Eventually(session).Should(Say("NAME:")) 808 Eventually(session).Should(Exit(1)) 809 }) 810 }) 811 }) 812 }) 813 }) 814 })