github.com/franc20/ayesa_sap@v7.0.0-beta.28.0.20200124003224-302d4d52fa6c+incompatible/command/v7/push_command_test.go (about) 1 package v7_test 2 3 import ( 4 "context" 5 "errors" 6 "time" 7 8 "code.cloudfoundry.org/cli/actor/actionerror" 9 "code.cloudfoundry.org/cli/actor/sharedaction" 10 "code.cloudfoundry.org/cli/actor/sharedaction/sharedactionfakes" 11 "code.cloudfoundry.org/cli/actor/v7action" 12 "code.cloudfoundry.org/cli/actor/v7pushaction" 13 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" 14 "code.cloudfoundry.org/cli/command/commandfakes" 15 "code.cloudfoundry.org/cli/command/flag" 16 "code.cloudfoundry.org/cli/command/translatableerror" 17 "code.cloudfoundry.org/cli/command/v6/v6fakes" 18 . "code.cloudfoundry.org/cli/command/v7" 19 "code.cloudfoundry.org/cli/command/v7/v7fakes" 20 "code.cloudfoundry.org/cli/types" 21 "code.cloudfoundry.org/cli/util/configv3" 22 "code.cloudfoundry.org/cli/util/manifestparser" 23 "code.cloudfoundry.org/cli/util/ui" 24 "github.com/cloudfoundry/bosh-cli/director/template" 25 . "github.com/onsi/ginkgo" 26 . "github.com/onsi/ginkgo/extensions/table" 27 . "github.com/onsi/gomega" 28 . "github.com/onsi/gomega/gbytes" 29 ) 30 31 type Step struct { 32 Plan v7pushaction.PushPlan 33 Error error 34 Event v7pushaction.Event 35 Warnings v7pushaction.Warnings 36 } 37 38 func FillInEvents(steps []Step) <-chan *v7pushaction.PushEvent { 39 eventStream := make(chan *v7pushaction.PushEvent) 40 41 go func() { 42 defer close(eventStream) 43 44 for _, step := range steps { 45 eventStream <- &v7pushaction.PushEvent{Plan: step.Plan, Warnings: step.Warnings, Err: step.Error, Event: step.Event} 46 } 47 }() 48 49 return eventStream 50 } 51 52 type LogEvent struct { 53 Log *sharedaction.LogMessage 54 Error error 55 } 56 57 func ReturnLogs(logevents []LogEvent, passedWarnings v7action.Warnings, passedError error) func(appName string, spaceGUID string, client sharedaction.LogCacheClient) (<-chan sharedaction.LogMessage, <-chan error, context.CancelFunc, v7action.Warnings, error) { 58 return func(appName string, spaceGUID string, client sharedaction.LogCacheClient) (<-chan sharedaction.LogMessage, <-chan error, context.CancelFunc, v7action.Warnings, error) { 59 logStream := make(chan sharedaction.LogMessage) 60 errStream := make(chan error) 61 go func() { 62 defer close(logStream) 63 defer close(errStream) 64 65 for _, log := range logevents { 66 if log.Log != nil { 67 logStream <- *log.Log 68 } 69 if log.Error != nil { 70 errStream <- log.Error 71 } 72 } 73 }() 74 75 return logStream, errStream, func() {}, passedWarnings, passedError 76 } 77 } 78 79 var _ = Describe("push Command", func() { 80 var ( 81 cmd PushCommand 82 input *Buffer 83 testUI *ui.UI 84 fakeConfig *commandfakes.FakeConfig 85 fakeSharedActor *commandfakes.FakeSharedActor 86 fakeActor *v7fakes.FakePushActor 87 fakeVersionActor *v7fakes.FakeV7ActorForPush 88 fakeProgressBar *v6fakes.FakeProgressBar 89 fakeLogCacheClient *sharedactionfakes.FakeLogCacheClient 90 fakeManifestLocator *v7fakes.FakeManifestLocator 91 fakeManifestParser *v7fakes.FakeManifestParser 92 binaryName string 93 executeErr error 94 95 appName1 string 96 appName2 string 97 userName string 98 spaceName string 99 orgName string 100 pwd string 101 ) 102 103 BeforeEach(func() { 104 input = NewBuffer() 105 testUI = ui.NewTestUI(input, NewBuffer(), NewBuffer()) 106 fakeConfig = new(commandfakes.FakeConfig) 107 fakeSharedActor = new(commandfakes.FakeSharedActor) 108 fakeActor = new(v7fakes.FakePushActor) 109 fakeVersionActor = new(v7fakes.FakeV7ActorForPush) 110 fakeProgressBar = new(v6fakes.FakeProgressBar) 111 fakeLogCacheClient = new(sharedactionfakes.FakeLogCacheClient) 112 113 appName1 = "first-app" 114 appName2 = "second-app" 115 userName = "some-user" 116 spaceName = "some-space" 117 orgName = "some-org" 118 pwd = "/push/cmd/test" 119 fakeManifestLocator = new(v7fakes.FakeManifestLocator) 120 fakeManifestParser = new(v7fakes.FakeManifestParser) 121 122 binaryName = "faceman" 123 fakeConfig.BinaryNameReturns(binaryName) 124 125 cmd = PushCommand{ 126 UI: testUI, 127 Config: fakeConfig, 128 Actor: fakeActor, 129 VersionActor: fakeVersionActor, 130 SharedActor: fakeSharedActor, 131 ProgressBar: fakeProgressBar, 132 LogCacheClient: fakeLogCacheClient, 133 CWD: pwd, 134 ManifestLocator: fakeManifestLocator, 135 ManifestParser: fakeManifestParser, 136 } 137 }) 138 139 Describe("Execute", func() { 140 JustBeforeEach(func() { 141 executeErr = cmd.Execute(nil) 142 }) 143 144 BeforeEach(func() { 145 fakeActor.ActualizeStub = func(v7pushaction.PushPlan, v7pushaction.ProgressBar) <-chan *v7pushaction.PushEvent { 146 return FillInEvents([]Step{}) 147 } 148 }) 149 150 When("checking target fails", func() { 151 BeforeEach(func() { 152 fakeSharedActor.CheckTargetReturns(actionerror.NoOrganizationTargetedError{BinaryName: binaryName}) 153 }) 154 155 It("returns an error", func() { 156 Expect(executeErr).To(MatchError(actionerror.NoOrganizationTargetedError{BinaryName: binaryName})) 157 158 Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1)) 159 checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0) 160 Expect(checkTargetedOrg).To(BeTrue()) 161 Expect(checkTargetedSpace).To(BeTrue()) 162 }) 163 }) 164 165 When("checking target fails because the user is not logged in", func() { 166 BeforeEach(func() { 167 fakeSharedActor.CheckTargetReturns(actionerror.NotLoggedInError{BinaryName: binaryName}) 168 }) 169 170 It("returns an error", func() { 171 Expect(executeErr).To(MatchError(actionerror.NotLoggedInError{BinaryName: binaryName})) 172 173 Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1)) 174 checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0) 175 Expect(checkTargetedOrg).To(BeTrue()) 176 Expect(checkTargetedSpace).To(BeTrue()) 177 }) 178 }) 179 180 When("the user is logged in, and org and space are targeted", func() { 181 BeforeEach(func() { 182 fakeConfig.CurrentUserReturns(configv3.User{Name: userName}, nil) 183 184 fakeConfig.TargetedOrganizationReturns(configv3.Organization{ 185 Name: orgName, 186 GUID: "some-org-guid", 187 }) 188 fakeConfig.TargetedSpaceReturns(configv3.Space{ 189 Name: spaceName, 190 GUID: "some-space-guid", 191 }) 192 }) 193 194 When("invalid flags are passed", func() { 195 BeforeEach(func() { 196 cmd.DockerUsername = "some-docker-username" 197 }) 198 199 It("returns a validation error", func() { 200 Expect(executeErr).To(MatchError(translatableerror.RequiredFlagsError{Arg1: "--docker-image, -o", Arg2: "--docker-username"})) 201 }) 202 }) 203 204 When("the flags are all valid", func() { 205 It("delegating to the GetBaseManifest", func() { 206 // This tells us GetBaseManifest is being called because we dont have a fake 207 Expect(fakeManifestLocator.PathCallCount()).To(Equal(1)) 208 }) 209 210 When("getting the base manifest fails", func() { 211 BeforeEach(func() { 212 fakeManifestLocator.PathReturns("", false, errors.New("locate-error")) 213 }) 214 215 It("returns the error", func() { 216 Expect(executeErr).To(MatchError(errors.New("locate-error"))) 217 }) 218 }) 219 220 When("getting the base manifest succeeds", func() { 221 BeforeEach(func() { 222 // essentially fakes GetBaseManifest 223 fakeManifestLocator.PathReturns("", true, nil) 224 fakeManifestParser.InterpolateAndParseReturns( 225 manifestparser.Manifest{ 226 Applications: []manifestparser.Application{ 227 { 228 Name: "some-app-name", 229 }, 230 }, 231 }, 232 nil, 233 ) 234 }) 235 236 It("delegates to the flag override handler", func() { 237 Expect(fakeActor.HandleFlagOverridesCallCount()).To(Equal(1)) 238 actualManifest, actualFlagOverrides := fakeActor.HandleFlagOverridesArgsForCall(0) 239 Expect(actualManifest).To(Equal( 240 manifestparser.Manifest{ 241 Applications: []manifestparser.Application{ 242 {Name: "some-app-name"}, 243 }, 244 }, 245 )) 246 Expect(actualFlagOverrides).To(Equal(v7pushaction.FlagOverrides{})) 247 }) 248 249 When("handling the flag overrides fails", func() { 250 BeforeEach(func() { 251 fakeActor.HandleFlagOverridesReturns(manifestparser.Manifest{}, errors.New("override-handler-error")) 252 }) 253 254 It("returns the error", func() { 255 Expect(executeErr).To(MatchError("override-handler-error")) 256 }) 257 }) 258 259 When("handling the flag overrides succeeds", func() { 260 BeforeEach(func() { 261 fakeActor.HandleFlagOverridesReturns( 262 manifestparser.Manifest{ 263 Applications: []manifestparser.Application{ 264 {Name: "some-app-name"}, 265 }, 266 }, 267 nil, 268 ) 269 }) 270 271 When("the docker password is needed", func() { 272 // TODO remove this in favor of a fake manifest 273 BeforeEach(func() { 274 fakeActor.HandleFlagOverridesReturns( 275 manifestparser.Manifest{ 276 Applications: []manifestparser.Application{ 277 { 278 Name: "some-app-name", 279 Docker: &manifestparser.Docker{Username: "username", Image: "image"}, 280 }, 281 }, 282 }, 283 nil, 284 ) 285 }) 286 287 It("delegates to the GetDockerPassword", func() { 288 Expect(fakeConfig.DockerPasswordCallCount()).To(Equal(1)) 289 }) 290 }) 291 292 It("delegates to the manifest parser", func() { 293 Expect(fakeManifestParser.MarshalManifestCallCount()).To(Equal(1)) 294 Expect(fakeManifestParser.MarshalManifestArgsForCall(0)).To(Equal( 295 manifestparser.Manifest{ 296 Applications: []manifestparser.Application{ 297 {Name: "some-app-name"}, 298 }, 299 }, 300 )) 301 }) 302 303 When("marshalling the manifest fails", func() { 304 BeforeEach(func() { 305 fakeManifestParser.MarshalManifestReturns([]byte{}, errors.New("marshal error")) 306 }) 307 308 It("returns the error", func() { 309 Expect(executeErr).To(MatchError("marshal error")) 310 }) 311 }) 312 313 When("marsahlling the manifest succeeds", func() { 314 BeforeEach(func() { 315 fakeManifestParser.MarshalManifestReturns([]byte("our-manifest"), nil) 316 }) 317 318 It("delegates to the version actor", func() { 319 Expect(fakeVersionActor.SetSpaceManifestCallCount()).To(Equal(1)) 320 actualSpaceGUID, actualManifestBytes := fakeVersionActor.SetSpaceManifestArgsForCall(0) 321 Expect(actualSpaceGUID).To(Equal("some-space-guid")) 322 Expect(actualManifestBytes).To(Equal([]byte("our-manifest"))) 323 }) 324 325 When("applying the manifest fails", func() { 326 BeforeEach(func() { 327 fakeVersionActor.SetSpaceManifestReturns(v7action.Warnings{"apply-manifest-warnings"}, errors.New("apply-manifest-error")) 328 }) 329 330 It("returns an error and prints warnings", func() { 331 Expect(executeErr).To(MatchError("apply-manifest-error")) 332 Expect(testUI.Err).To(Say("apply-manifest-warnings")) 333 }) 334 335 }) 336 337 When("applying the manifest succeeds", func() { 338 BeforeEach(func() { 339 fakeVersionActor.SetSpaceManifestReturns(v7action.Warnings{"apply-manifest-warnings"}, nil) 340 }) 341 342 It("delegates to the push actor", func() { 343 Expect(fakeActor.CreatePushPlansCallCount()).To(Equal(1)) 344 spaceGUID, orgGUID, manifest, overrides := fakeActor.CreatePushPlansArgsForCall(0) 345 Expect(spaceGUID).To(Equal("some-space-guid")) 346 Expect(orgGUID).To(Equal("some-org-guid")) 347 Expect(manifest).To(Equal( 348 manifestparser.Manifest{ 349 Applications: []manifestparser.Application{ 350 {Name: "some-app-name"}, 351 }, 352 }, 353 )) 354 Expect(overrides).To(Equal(v7pushaction.FlagOverrides{})) 355 }) 356 357 When("creating the push plans fails", func() { 358 BeforeEach(func() { 359 fakeActor.CreatePushPlansReturns( 360 nil, 361 v7action.Warnings{"create-push-plans-warnings"}, 362 errors.New("create-push-plans-error"), 363 ) 364 }) 365 366 It("returns errors and warnings", func() { 367 Expect(executeErr).To(MatchError("create-push-plans-error")) 368 Expect(testUI.Err).To(Say("create-push-plans-warnings")) 369 }) 370 371 }) 372 373 When("creating the push plans succeeds", func() { 374 BeforeEach(func() { 375 fakeActor.CreatePushPlansReturns( 376 []v7pushaction.PushPlan{ 377 v7pushaction.PushPlan{Application: v7action.Application{Name: "first-app", GUID: "potato"}}, 378 v7pushaction.PushPlan{Application: v7action.Application{Name: "second-app", GUID: "potato"}}, 379 }, 380 v7action.Warnings{"create-push-plans-warnings"}, 381 nil, 382 ) 383 }) 384 385 It("it displays the warnings from create push plans", func() { 386 Expect(testUI.Err).To(Say("create-push-plans-warnings")) 387 }) 388 389 Describe("delegating to Actor.Actualize", func() { 390 When("Actualize returns success", func() { 391 BeforeEach(func() { 392 fakeActor.ActualizeStub = func(v7pushaction.PushPlan, v7pushaction.ProgressBar) <-chan *v7pushaction.PushEvent { 393 return FillInEvents([]Step{ 394 {Plan: v7pushaction.PushPlan{Application: v7action.Application{GUID: "potato"}}}, 395 }) 396 } 397 }) 398 399 Describe("actualize events", func() { 400 BeforeEach(func() { 401 fakeActor.ActualizeStub = func(pushPlan v7pushaction.PushPlan, _ v7pushaction.ProgressBar) <-chan *v7pushaction.PushEvent { 402 return FillInEvents([]Step{ 403 { 404 Plan: v7pushaction.PushPlan{Application: v7action.Application{GUID: pushPlan.Application.GUID, Name: pushPlan.Application.Name}}, 405 Event: v7pushaction.CreatingArchive, 406 }, 407 { 408 Plan: v7pushaction.PushPlan{Application: v7action.Application{GUID: pushPlan.Application.GUID, Name: pushPlan.Application.Name}}, 409 Event: v7pushaction.UploadingApplicationWithArchive, 410 Warnings: v7pushaction.Warnings{"upload app archive warning"}, 411 }, 412 { 413 Plan: v7pushaction.PushPlan{Application: v7action.Application{GUID: pushPlan.Application.GUID, Name: pushPlan.Application.Name}}, 414 Event: v7pushaction.RetryUpload, 415 Warnings: v7pushaction.Warnings{"retry upload warning"}, 416 }, 417 { 418 Plan: v7pushaction.PushPlan{Application: v7action.Application{GUID: pushPlan.Application.GUID, Name: pushPlan.Application.Name}}, 419 Event: v7pushaction.UploadWithArchiveComplete, 420 }, 421 { 422 Plan: v7pushaction.PushPlan{Application: v7action.Application{GUID: pushPlan.Application.GUID, Name: pushPlan.Application.Name}}, 423 Event: v7pushaction.RestartingApplication, 424 }, 425 { 426 Plan: v7pushaction.PushPlan{Application: v7action.Application{GUID: pushPlan.Application.GUID, Name: pushPlan.Application.Name}}, 427 Event: v7pushaction.StartingDeployment, 428 }, 429 { 430 Plan: v7pushaction.PushPlan{Application: v7action.Application{GUID: pushPlan.Application.GUID, Name: pushPlan.Application.Name}}, 431 Event: v7pushaction.WaitingForDeployment, 432 }, 433 }) 434 } 435 }) 436 437 It("actualizes the application and displays events/warnings", func() { 438 Expect(executeErr).ToNot(HaveOccurred()) 439 440 Expect(fakeProgressBar.ReadyCallCount()).Should(Equal(2)) 441 Expect(fakeProgressBar.CompleteCallCount()).Should(Equal(2)) 442 443 Expect(testUI.Out).To(Say("Packaging files to upload...")) 444 445 Expect(testUI.Out).To(Say("Uploading files...")) 446 Expect(testUI.Err).To(Say("upload app archive warning")) 447 448 Expect(testUI.Out).To(Say("Retrying upload due to an error...")) 449 Expect(testUI.Err).To(Say("retry upload warning")) 450 451 Expect(testUI.Out).To(Say("Waiting for API to complete processing files...")) 452 453 Expect(testUI.Out).To(Say("Waiting for app first-app to start...")) 454 455 Expect(testUI.Out).To(Say("Packaging files to upload...")) 456 457 Expect(testUI.Out).To(Say("Uploading files...")) 458 Expect(testUI.Err).To(Say("upload app archive warning")) 459 460 Expect(testUI.Out).To(Say("Retrying upload due to an error...")) 461 Expect(testUI.Err).To(Say("retry upload warning")) 462 463 Expect(testUI.Out).To(Say("Waiting for API to complete processing files...")) 464 465 Expect(testUI.Out).To(Say("Waiting for app second-app to start...")) 466 467 Expect(testUI.Out).To(Say("Starting deployment for app second-app...")) 468 469 Expect(testUI.Out).To(Say("Waiting for app to deploy...")) 470 }) 471 }) 472 473 Describe("staging logs", func() { 474 BeforeEach(func() { 475 fakeActor.ActualizeStub = func(pushPlan v7pushaction.PushPlan, _ v7pushaction.ProgressBar) <-chan *v7pushaction.PushEvent { 476 return FillInEvents([]Step{ 477 {Plan: pushPlan, Event: v7pushaction.StartingStaging}, 478 }) 479 } 480 }) 481 482 When("there are no logging errors", func() { 483 BeforeEach(func() { 484 fakeVersionActor.GetStreamingLogsForApplicationByNameAndSpaceStub = ReturnLogs( 485 []LogEvent{ 486 {Log: sharedaction.NewLogMessage("log-message-1", "OUT", time.Now(), sharedaction.StagingLog, "source-instance")}, 487 {Log: sharedaction.NewLogMessage("log-message-2", "OUT", time.Now(), sharedaction.StagingLog, "source-instance")}, 488 {Log: sharedaction.NewLogMessage("log-message-3", "OUT", time.Now(), "potato", "source-instance")}, 489 }, 490 v7action.Warnings{"log-warning-1", "log-warning-2"}, 491 nil, 492 ) 493 }) 494 495 It("displays the staging logs and warnings", func() { 496 Expect(testUI.Out).To(Say("Staging app and tracing logs...")) 497 498 Expect(testUI.Err).To(Say("log-warning-1")) 499 Expect(testUI.Err).To(Say("log-warning-2")) 500 501 Eventually(testUI.Out).Should(Say("log-message-1")) 502 Eventually(testUI.Out).Should(Say("log-message-2")) 503 Eventually(testUI.Out).ShouldNot(Say("log-message-3")) 504 505 Expect(fakeVersionActor.GetStreamingLogsForApplicationByNameAndSpaceCallCount()).To(Equal(2)) 506 passedAppName, spaceGUID, _ := fakeVersionActor.GetStreamingLogsForApplicationByNameAndSpaceArgsForCall(0) 507 Expect(passedAppName).To(Equal(appName1)) 508 Expect(spaceGUID).To(Equal("some-space-guid")) 509 passedAppName, spaceGUID, _ = fakeVersionActor.GetStreamingLogsForApplicationByNameAndSpaceArgsForCall(1) 510 Expect(passedAppName).To(Equal(appName2)) 511 Expect(spaceGUID).To(Equal("some-space-guid")) 512 513 }) 514 }) 515 516 When("there are logging errors", func() { 517 BeforeEach(func() { 518 fakeVersionActor.GetStreamingLogsForApplicationByNameAndSpaceStub = ReturnLogs( 519 []LogEvent{ 520 {Error: errors.New("some-random-err")}, 521 {Error: actionerror.LogCacheTimeoutError{}}, 522 {Log: sharedaction.NewLogMessage("log-message-1", "OUT", time.Now(), sharedaction.StagingLog, "source-instance")}, 523 }, 524 v7action.Warnings{"log-warning-1", "log-warning-2"}, 525 nil, 526 ) 527 }) 528 529 It("displays the errors as warnings", func() { 530 Expect(testUI.Out).To(Say("Staging app and tracing logs...")) 531 532 Expect(testUI.Err).To(Say("log-warning-1")) 533 Expect(testUI.Err).To(Say("log-warning-2")) 534 Eventually(testUI.Err).Should(Say("some-random-err")) 535 Eventually(testUI.Err).Should(Say("timeout connecting to log server, no log will be shown")) 536 537 Eventually(testUI.Out).Should(Say("log-message-1")) 538 }) 539 }) 540 }) 541 542 When("when getting the application summary succeeds", func() { 543 BeforeEach(func() { 544 summary := v7action.DetailedApplicationSummary{ 545 ApplicationSummary: v7action.ApplicationSummary{ 546 Application: v7action.Application{}, 547 ProcessSummaries: v7action.ProcessSummaries{}, 548 }, 549 CurrentDroplet: v7action.Droplet{}, 550 } 551 fakeVersionActor.GetDetailedAppSummaryReturnsOnCall(0, summary, v7action.Warnings{"app-1-summary-warning-1", "app-1-summary-warning-2"}, nil) 552 fakeVersionActor.GetDetailedAppSummaryReturnsOnCall(1, summary, v7action.Warnings{"app-2-summary-warning-1", "app-2-summary-warning-2"}, nil) 553 }) 554 555 // TODO: Don't test the shared.AppSummaryDisplayer.AppDisplay method. 556 // Use DI to pass in a new AppSummaryDisplayer to the Command instead. 557 It("displays the app summary", func() { 558 Expect(executeErr).ToNot(HaveOccurred()) 559 Expect(fakeVersionActor.GetDetailedAppSummaryCallCount()).To(Equal(2)) 560 }) 561 }) 562 563 When("getting the application summary fails", func() { 564 BeforeEach(func() { 565 fakeVersionActor.GetDetailedAppSummaryReturns( 566 v7action.DetailedApplicationSummary{}, 567 v7action.Warnings{"get-application-summary-warnings"}, 568 errors.New("get-application-summary-error"), 569 ) 570 }) 571 572 It("does not display the app summary", func() { 573 Expect(testUI.Out).ToNot(Say(`requested state:`)) 574 }) 575 576 It("returns the error from GetDetailedAppSummary", func() { 577 Expect(executeErr).To(MatchError("get-application-summary-error")) 578 }) 579 580 It("prints the warnings", func() { 581 Expect(testUI.Err).To(Say("get-application-summary-warnings")) 582 }) 583 }) 584 585 }) 586 587 When("actualize returns an error", func() { 588 When("the error is generic", func() { 589 BeforeEach(func() { 590 fakeActor.ActualizeStub = func(v7pushaction.PushPlan, v7pushaction.ProgressBar) <-chan *v7pushaction.PushEvent { 591 return FillInEvents([]Step{ 592 {Error: errors.New("anti avant garde naming")}, 593 }) 594 } 595 }) 596 597 It("returns the error", func() { 598 Expect(executeErr).To(MatchError("anti avant garde naming")) 599 }) 600 }) 601 602 When("the error is a startup timeout error", func() { 603 BeforeEach(func() { 604 fakeActor.ActualizeStub = func(v7pushaction.PushPlan, v7pushaction.ProgressBar) <-chan *v7pushaction.PushEvent { 605 return FillInEvents([]Step{ 606 {Error: actionerror.StartupTimeoutError{}}, 607 }) 608 } 609 }) 610 611 It("returns the StartupTimeoutError and prints warnings", func() { 612 Expect(executeErr).To(MatchError(translatableerror.StartupTimeoutError{ 613 AppName: "first-app", 614 BinaryName: binaryName, 615 })) 616 }) 617 }) 618 619 When("the error is a process crashed error", func() { 620 BeforeEach(func() { 621 fakeActor.ActualizeStub = func(v7pushaction.PushPlan, v7pushaction.ProgressBar) <-chan *v7pushaction.PushEvent { 622 return FillInEvents([]Step{ 623 {Error: actionerror.AllInstancesCrashedError{}}, 624 }) 625 } 626 }) 627 628 It("returns the ApplicationUnableToStartError", func() { 629 Expect(executeErr).To(MatchError(translatableerror.ApplicationUnableToStartError{ 630 AppName: "first-app", 631 BinaryName: binaryName, 632 })) 633 }) 634 635 It("displays the app summary", func() { 636 Expect(executeErr).To(HaveOccurred()) 637 Expect(fakeVersionActor.GetDetailedAppSummaryCallCount()).To(Equal(1)) 638 }) 639 }) 640 }) 641 }) 642 }) 643 }) 644 }) 645 }) 646 }) 647 }) 648 }) 649 }) 650 651 Describe("GetDockerPassword", func() { 652 var ( 653 cmd PushCommand 654 fakeConfig *commandfakes.FakeConfig 655 testUI *ui.UI 656 657 dockerUsername string 658 containsPrivateDocker bool 659 660 executeErr error 661 dockerPassword string 662 663 input *Buffer 664 ) 665 666 BeforeEach(func() { 667 input = NewBuffer() 668 testUI = ui.NewTestUI(input, NewBuffer(), NewBuffer()) 669 fakeConfig = new(commandfakes.FakeConfig) 670 671 cmd = PushCommand{ 672 Config: fakeConfig, 673 UI: testUI, 674 } 675 }) 676 677 Describe("Get", func() { 678 JustBeforeEach(func() { 679 dockerPassword, executeErr = cmd.GetDockerPassword(dockerUsername, containsPrivateDocker) 680 }) 681 682 When("docker image is private", func() { 683 When("there is a manifest", func() { 684 BeforeEach(func() { 685 dockerUsername = "" 686 containsPrivateDocker = true 687 }) 688 689 When("a password is provided via environment variable", func() { 690 BeforeEach(func() { 691 fakeConfig.DockerPasswordReturns("some-docker-password") 692 }) 693 694 It("takes the password from the environment", func() { 695 Expect(executeErr).ToNot(HaveOccurred()) 696 697 Expect(testUI.Out).ToNot(Say("Environment variable CF_DOCKER_PASSWORD not set.")) 698 Expect(testUI.Out).ToNot(Say("Docker password")) 699 700 Expect(testUI.Out).To(Say("Using docker repository password from environment variable CF_DOCKER_PASSWORD.")) 701 702 Expect(dockerPassword).To(Equal("some-docker-password")) 703 }) 704 }) 705 706 When("no password is provided", func() { 707 BeforeEach(func() { 708 _, err := input.Write([]byte("some-docker-password\n")) 709 Expect(err).ToNot(HaveOccurred()) 710 }) 711 712 It("prompts for a password", func() { 713 Expect(executeErr).ToNot(HaveOccurred()) 714 715 Expect(testUI.Out).To(Say("Environment variable CF_DOCKER_PASSWORD not set.")) 716 Expect(testUI.Out).To(Say("Docker password")) 717 718 Expect(dockerPassword).To(Equal("some-docker-password")) 719 }) 720 }) 721 }) 722 723 When("there is no manifest", func() { 724 BeforeEach(func() { 725 dockerUsername = "some-docker-username" 726 containsPrivateDocker = false 727 }) 728 729 When("a password is provided via environment variable", func() { 730 BeforeEach(func() { 731 fakeConfig.DockerPasswordReturns("some-docker-password") 732 }) 733 734 It("takes the password from the environment", func() { 735 Expect(executeErr).ToNot(HaveOccurred()) 736 737 Expect(testUI.Out).ToNot(Say("Environment variable CF_DOCKER_PASSWORD not set.")) 738 Expect(testUI.Out).ToNot(Say("Docker password")) 739 740 Expect(testUI.Out).To(Say("Using docker repository password from environment variable CF_DOCKER_PASSWORD.")) 741 742 Expect(dockerPassword).To(Equal("some-docker-password")) 743 }) 744 }) 745 746 When("no password is provided", func() { 747 BeforeEach(func() { 748 _, err := input.Write([]byte("some-docker-password\n")) 749 Expect(err).ToNot(HaveOccurred()) 750 }) 751 752 It("prompts for a password", func() { 753 Expect(executeErr).ToNot(HaveOccurred()) 754 755 Expect(testUI.Out).To(Say("Environment variable CF_DOCKER_PASSWORD not set.")) 756 Expect(testUI.Out).To(Say("Docker password")) 757 758 Expect(dockerPassword).To(Equal("some-docker-password")) 759 }) 760 }) 761 }) 762 }) 763 When("docker image is public", func() { 764 BeforeEach(func() { 765 dockerUsername = "" 766 containsPrivateDocker = false 767 }) 768 769 It("does not prompt for a password", func() { 770 Expect(testUI.Out).ToNot(Say("Environment variable CF_DOCKER_PASSWORD not set.")) 771 Expect(testUI.Out).ToNot(Say("Docker password")) 772 Expect(testUI.Out).ToNot(Say("Using docker repository password from environment variable CF_DOCKER_PASSWORD.")) 773 }) 774 775 It("returns an empty password", func() { 776 Expect(executeErr).ToNot(HaveOccurred()) 777 Expect(dockerPassword).To(Equal("")) 778 }) 779 }) 780 }) 781 }) 782 783 Describe("GetBaseManifest", func() { 784 var ( 785 somePath string 786 flagOverrides v7pushaction.FlagOverrides 787 manifest manifestparser.Manifest 788 executeErr error 789 ) 790 791 JustBeforeEach(func() { 792 manifest, executeErr = cmd.GetBaseManifest(flagOverrides) 793 }) 794 795 When("no flags are specified", func() { 796 BeforeEach(func() { 797 cmd.CWD = somePath 798 }) 799 800 When("a manifest exists in the current dir", func() { 801 BeforeEach(func() { 802 fakeManifestLocator.PathReturns("/manifest/path", true, nil) 803 fakeManifestParser.InterpolateAndParseReturns( 804 manifestparser.Manifest{ 805 Applications: []manifestparser.Application{ 806 {Name: "new-app"}, 807 }, 808 }, 809 nil, 810 ) 811 }) 812 813 It("uses the manifest in the current directory", func() { 814 Expect(executeErr).ToNot(HaveOccurred()) 815 Expect(manifest).To(Equal( 816 manifestparser.Manifest{ 817 Applications: []manifestparser.Application{ 818 {Name: "new-app"}, 819 }, 820 }), 821 ) 822 823 Expect(fakeManifestLocator.PathCallCount()).To(Equal(1)) 824 Expect(fakeManifestLocator.PathArgsForCall(0)).To(Equal(cmd.CWD)) 825 826 Expect(fakeManifestParser.InterpolateAndParseCallCount()).To(Equal(1)) 827 actualManifestPath, _, _ := fakeManifestParser.InterpolateAndParseArgsForCall(0) 828 Expect(actualManifestPath).To(Equal("/manifest/path")) 829 }) 830 }) 831 832 When("there is not a manifest in the current dir", func() { 833 BeforeEach(func() { 834 flagOverrides.AppName = "new-app" 835 fakeManifestLocator.PathReturns("", false, nil) 836 }) 837 838 It("ignores the file not found error", func() { 839 Expect(executeErr).ToNot(HaveOccurred()) 840 Expect(fakeManifestParser.InterpolateAndParseCallCount()).To(Equal(0)) 841 }) 842 843 It("returns a default empty manifest", func() { 844 Expect(manifest).To(Equal( 845 manifestparser.Manifest{ 846 Applications: []manifestparser.Application{ 847 {Name: "new-app"}, 848 }, 849 }), 850 ) 851 }) 852 }) 853 854 When("when there is an error locating the manifest in the current directory", func() { 855 BeforeEach(func() { 856 fakeManifestLocator.PathReturns("", false, errors.New("err-location")) 857 }) 858 859 It("returns the error", func() { 860 Expect(executeErr).To(MatchError("err-location")) 861 Expect(fakeManifestParser.InterpolateAndParseCallCount()).To(Equal(0)) 862 }) 863 }) 864 865 When("parsing the manifest fails", func() { 866 BeforeEach(func() { 867 fakeManifestLocator.PathReturns("/manifest/path", true, nil) 868 fakeManifestParser.InterpolateAndParseReturns( 869 manifestparser.Manifest{}, 870 errors.New("bad yaml"), 871 ) 872 }) 873 874 It("returns the error", func() { 875 Expect(executeErr).To(MatchError("bad yaml")) 876 Expect(fakeManifestParser.InterpolateAndParseCallCount()).To(Equal(1)) 877 }) 878 }) 879 }) 880 881 When("The -f flag is specified", func() { 882 BeforeEach(func() { 883 somePath = "some-path" 884 flagOverrides.ManifestPath = somePath 885 fakeManifestLocator.PathReturns("/manifest/path", true, nil) 886 fakeManifestParser.InterpolateAndParseReturns( 887 manifestparser.Manifest{ 888 Applications: []manifestparser.Application{ 889 {Name: "new-app"}, 890 }, 891 }, 892 nil, 893 ) 894 }) 895 896 It("parses the specified manifest", func() { 897 Expect(executeErr).ToNot(HaveOccurred()) 898 899 Expect(fakeManifestLocator.PathCallCount()).To(Equal(1)) 900 Expect(fakeManifestLocator.PathArgsForCall(0)).To(Equal(somePath)) 901 902 Expect(fakeManifestParser.InterpolateAndParseCallCount()).To(Equal(1)) 903 actualManifestPath, _, _ := fakeManifestParser.InterpolateAndParseArgsForCall(0) 904 Expect(actualManifestPath).To(Equal("/manifest/path")) 905 Expect(manifest).To(Equal( 906 manifestparser.Manifest{ 907 Applications: []manifestparser.Application{ 908 {Name: "new-app"}, 909 }, 910 }), 911 ) 912 }) 913 }) 914 915 When("--vars-files are specified", func() { 916 var varsFiles []string 917 918 BeforeEach(func() { 919 fakeManifestLocator.PathReturns("/manifest/path", true, nil) 920 varsFiles = []string{"path1", "path2"} 921 flagOverrides.PathsToVarsFiles = append(flagOverrides.PathsToVarsFiles, varsFiles...) 922 }) 923 924 It("passes vars files to the manifest parser", func() { 925 Expect(executeErr).ToNot(HaveOccurred()) 926 927 Expect(fakeManifestParser.InterpolateAndParseCallCount()).To(Equal(1)) 928 _, actualVarsFiles, _ := fakeManifestParser.InterpolateAndParseArgsForCall(0) 929 Expect(actualVarsFiles).To(Equal(varsFiles)) 930 }) 931 }) 932 933 When("The --var flag is provided", func() { 934 var vars []template.VarKV 935 936 BeforeEach(func() { 937 fakeManifestLocator.PathReturns("/manifest/path", true, nil) 938 vars = []template.VarKV{ 939 {Name: "put-var-here", Value: "turtle"}, 940 } 941 flagOverrides.Vars = vars 942 }) 943 944 It("passes vars files to the manifest parser", func() { 945 Expect(executeErr).ToNot(HaveOccurred()) 946 947 Expect(fakeManifestParser.InterpolateAndParseCallCount()).To(Equal(1)) 948 _, _, actualVars := fakeManifestParser.InterpolateAndParseArgsForCall(0) 949 Expect(actualVars).To(Equal(vars)) 950 }) 951 }) 952 }) 953 954 Describe("GetFlagOverrides", func() { 955 var ( 956 overrides v7pushaction.FlagOverrides 957 overridesErr error 958 ) 959 960 BeforeEach(func() { 961 cmd.Buildpacks = []string{"buildpack-1", "buildpack-2"} 962 cmd.Stack = "validStack" 963 cmd.HealthCheckType = flag.HealthCheckType{Type: constant.Port} 964 cmd.HealthCheckHTTPEndpoint = "/health-check-http-endpoint" 965 cmd.HealthCheckTimeout = flag.PositiveInteger{Value: 7} 966 cmd.Memory = "64M" 967 cmd.Disk = "256M" 968 cmd.DropletPath = flag.PathWithExistenceCheck("some-droplet.tgz") 969 cmd.StartCommand = flag.Command{FilteredString: types.FilteredString{IsSet: true, Value: "some-start-command"}} 970 cmd.NoRoute = true 971 cmd.RandomRoute = false 972 cmd.NoStart = true 973 cmd.NoWait = true 974 cmd.Strategy = flag.DeploymentStrategy{Name: constant.DeploymentStrategyRolling} 975 cmd.Instances = flag.Instances{NullInt: types.NullInt{Value: 10, IsSet: true}} 976 cmd.PathToManifest = "/manifest/path" 977 cmd.PathsToVarsFiles = []flag.PathWithExistenceCheck{"/vars1", "/vars2"} 978 cmd.Vars = []template.VarKV{{Name: "key", Value: "val"}} 979 cmd.Task = true 980 }) 981 982 JustBeforeEach(func() { 983 overrides, overridesErr = cmd.GetFlagOverrides() 984 Expect(overridesErr).ToNot(HaveOccurred()) 985 }) 986 987 It("sets them on the flag overrides", func() { 988 Expect(overridesErr).ToNot(HaveOccurred()) 989 Expect(overrides.Buildpacks).To(ConsistOf("buildpack-1", "buildpack-2")) 990 Expect(overrides.DropletPath).To(Equal("some-droplet.tgz")) 991 Expect(overrides.Stack).To(Equal("validStack")) 992 Expect(overrides.HealthCheckType).To(Equal(constant.Port)) 993 Expect(overrides.HealthCheckEndpoint).To(Equal("/health-check-http-endpoint")) 994 Expect(overrides.HealthCheckTimeout).To(BeEquivalentTo(7)) 995 Expect(overrides.Memory).To(Equal("64M")) 996 Expect(overrides.Disk).To(Equal("256M")) 997 Expect(overrides.StartCommand).To(Equal(types.FilteredString{IsSet: true, Value: "some-start-command"})) 998 Expect(overrides.NoRoute).To(BeTrue()) 999 Expect(overrides.NoStart).To(BeTrue()) 1000 Expect(overrides.NoWait).To(BeTrue()) 1001 Expect(overrides.RandomRoute).To(BeFalse()) 1002 Expect(overrides.Strategy).To(Equal(constant.DeploymentStrategyRolling)) 1003 Expect(overrides.Instances).To(Equal(types.NullInt{Value: 10, IsSet: true})) 1004 Expect(overrides.ManifestPath).To(Equal("/manifest/path")) 1005 Expect(overrides.PathsToVarsFiles).To(Equal([]string{"/vars1", "/vars2"})) 1006 Expect(overrides.Vars).To(Equal([]template.VarKV{{Name: "key", Value: "val"}})) 1007 Expect(overrides.Task).To(BeTrue()) 1008 }) 1009 1010 When("a docker image is provided", func() { 1011 BeforeEach(func() { 1012 cmd.DockerImage = flag.DockerImage{Path: "some-docker-image"} 1013 }) 1014 1015 It("sets docker image on the flag overrides", func() { 1016 Expect(overridesErr).ToNot(HaveOccurred()) 1017 Expect(overrides.DockerImage).To(Equal("some-docker-image")) 1018 }) 1019 }) 1020 }) 1021 1022 DescribeTable("ValidateFlags returns an error", 1023 func(setup func(), expectedErr error) { 1024 setup() 1025 err := cmd.ValidateFlags() 1026 if expectedErr == nil { 1027 Expect(err).To(BeNil()) 1028 } else { 1029 Expect(err).To(MatchError(expectedErr)) 1030 } 1031 }, 1032 1033 Entry("when docker username flag is passed *without* docker flag", 1034 func() { 1035 cmd.DockerUsername = "some-docker-username" 1036 }, 1037 translatableerror.RequiredFlagsError{Arg1: "--docker-image, -o", Arg2: "--docker-username"}), 1038 1039 Entry("when docker and buildpacks flags are passed", 1040 func() { 1041 cmd.DockerImage.Path = "some-docker-image" 1042 cmd.Buildpacks = []string{"some-buildpack"} 1043 }, 1044 translatableerror.ArgumentCombinationError{Args: []string{"--buildpack, -b", "--docker-image, -o"}}), 1045 1046 Entry("when docker and stack flags are passed", 1047 func() { 1048 cmd.DockerImage.Path = "some-docker-image" 1049 cmd.Stack = "validStack" 1050 }, 1051 translatableerror.ArgumentCombinationError{Args: []string{"--stack, -s", "--docker-image, -o"}}), 1052 1053 Entry("when docker and path flags are passed", 1054 func() { 1055 cmd.DockerImage.Path = "some-docker-image" 1056 cmd.AppPath = "some-directory-path" 1057 }, 1058 translatableerror.ArgumentCombinationError{Args: []string{"--docker-image, -o", "--path, -p"}}), 1059 1060 Entry("when -u http does not have a matching --endpoint", 1061 func() { 1062 cmd.HealthCheckType.Type = constant.HTTP 1063 }, 1064 translatableerror.RequiredFlagsError{Arg1: "--endpoint", Arg2: "--health-check-type=http, -u=http"}), 1065 1066 Entry("when -u http does have a matching --endpoint", 1067 func() { 1068 cmd.HealthCheckType.Type = constant.HTTP 1069 cmd.HealthCheckHTTPEndpoint = "/health" 1070 }, 1071 nil), 1072 1073 Entry("when droplet and path flags are passed", 1074 func() { 1075 cmd.DropletPath = "some-droplet.tgz" 1076 cmd.AppPath = "/my/app" 1077 }, 1078 translatableerror.ArgumentCombinationError{ 1079 Args: []string{ 1080 "--droplet", "--docker-image, -o", "--docker-username", "-p", 1081 }, 1082 }), 1083 1084 Entry("when droplet and docker image flags are passed", 1085 func() { 1086 cmd.DropletPath = "some-droplet.tgz" 1087 cmd.DockerImage.Path = "docker-image" 1088 }, 1089 translatableerror.ArgumentCombinationError{ 1090 Args: []string{ 1091 "--droplet", "--docker-image, -o", "--docker-username", "-p", 1092 }, 1093 }), 1094 1095 Entry("when droplet, docker image, and docker username flags are passed", 1096 func() { 1097 cmd.DropletPath = "some-droplet.tgz" 1098 cmd.DockerImage.Path = "docker-image" 1099 cmd.DockerUsername = "docker-username" 1100 }, 1101 translatableerror.ArgumentCombinationError{ 1102 Args: []string{ 1103 "--droplet", "--docker-image, -o", "--docker-username", "-p", 1104 }, 1105 }), 1106 1107 Entry("when strategy 'rolling' and no-start flags are passed", 1108 func() { 1109 cmd.Strategy = flag.DeploymentStrategy{Name: constant.DeploymentStrategyRolling} 1110 cmd.NoStart = true 1111 }, 1112 translatableerror.ArgumentCombinationError{ 1113 Args: []string{ 1114 "--no-start", "--strategy=rolling", 1115 }, 1116 }), 1117 1118 Entry("when strategy is not set and no-start flags are passed", 1119 func() { 1120 cmd.Strategy = flag.DeploymentStrategy{Name: constant.DeploymentStrategyDefault} 1121 cmd.NoStart = true 1122 }, 1123 nil), 1124 1125 Entry("when no-start and no-wait flags are passed", 1126 func() { 1127 cmd.NoStart = true 1128 cmd.NoWait = true 1129 }, 1130 translatableerror.ArgumentCombinationError{ 1131 Args: []string{ 1132 "--no-start", "--no-wait", 1133 }, 1134 }), 1135 Entry("when no-route and random-route flags are passed", 1136 func() { 1137 cmd.NoRoute = true 1138 cmd.RandomRoute = true 1139 }, 1140 translatableerror.ArgumentCombinationError{ 1141 Args: []string{ 1142 "--no-route", "--random-route", 1143 }, 1144 }), 1145 1146 Entry("default is combined with non default buildpacks", 1147 func() { 1148 cmd.Buildpacks = []string{"some-docker-username", "default"} 1149 }, 1150 translatableerror.InvalidBuildpacksError{}), 1151 1152 Entry("default is combined with non default buildpacks", 1153 func() { 1154 cmd.Buildpacks = []string{"some-docker-username", "null"} 1155 }, 1156 translatableerror.InvalidBuildpacksError{}), 1157 1158 Entry("task and strategy flags are passed", 1159 func() { 1160 cmd.Task = true 1161 cmd.Strategy = flag.DeploymentStrategy{Name: constant.DeploymentStrategyRolling} 1162 }, 1163 translatableerror.ArgumentCombinationError{ 1164 Args: []string{ 1165 "--task", "--strategy=rolling", 1166 }, 1167 }), 1168 ) 1169 })