github.com/liamawhite/cli-with-i18n@v6.32.1-0.20171122084555-dede0a5c3448+incompatible/command/v2/v2_push_command_test.go (about) 1 package v2_test 2 3 import ( 4 "errors" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "regexp" 9 "time" 10 11 "github.com/liamawhite/cli-with-i18n/actor/pushaction" 12 "github.com/liamawhite/cli-with-i18n/actor/sharedaction" 13 "github.com/liamawhite/cli-with-i18n/actor/v2action" 14 "github.com/liamawhite/cli-with-i18n/api/cloudcontroller/ccv2" 15 "github.com/liamawhite/cli-with-i18n/command/commandfakes" 16 "github.com/liamawhite/cli-with-i18n/command/flag" 17 "github.com/liamawhite/cli-with-i18n/command/translatableerror" 18 . "github.com/liamawhite/cli-with-i18n/command/v2" 19 "github.com/liamawhite/cli-with-i18n/command/v2/v2fakes" 20 "github.com/liamawhite/cli-with-i18n/types" 21 "github.com/liamawhite/cli-with-i18n/util/configv3" 22 "github.com/liamawhite/cli-with-i18n/util/manifest" 23 "github.com/liamawhite/cli-with-i18n/util/ui" 24 . "github.com/onsi/ginkgo" 25 . "github.com/onsi/gomega" 26 . "github.com/onsi/gomega/gbytes" 27 ) 28 29 var _ = Describe("v2-push Command", func() { 30 var ( 31 cmd V2PushCommand 32 testUI *ui.UI 33 fakeConfig *commandfakes.FakeConfig 34 fakeSharedActor *commandfakes.FakeSharedActor 35 fakeActor *v2fakes.FakeV2PushActor 36 fakeRestartActor *v2fakes.FakeRestartActor 37 fakeProgressBar *v2fakes.FakeProgressBar 38 input *Buffer 39 binaryName string 40 41 appName string 42 executeErr error 43 pwd string 44 ) 45 46 BeforeEach(func() { 47 input = NewBuffer() 48 testUI = ui.NewTestUI(input, NewBuffer(), NewBuffer()) 49 fakeConfig = new(commandfakes.FakeConfig) 50 fakeSharedActor = new(commandfakes.FakeSharedActor) 51 fakeActor = new(v2fakes.FakeV2PushActor) 52 fakeRestartActor = new(v2fakes.FakeRestartActor) 53 fakeProgressBar = new(v2fakes.FakeProgressBar) 54 55 cmd = V2PushCommand{ 56 UI: testUI, 57 Config: fakeConfig, 58 SharedActor: fakeSharedActor, 59 Actor: fakeActor, 60 RestartActor: fakeRestartActor, 61 ProgressBar: fakeProgressBar, 62 } 63 64 appName = "some-app" 65 cmd.OptionalArgs.AppName = appName 66 binaryName = "faceman" 67 fakeConfig.BinaryNameReturns(binaryName) 68 69 var err error 70 pwd, err = os.Getwd() 71 Expect(err).ToNot(HaveOccurred()) 72 }) 73 74 JustBeforeEach(func() { 75 executeErr = cmd.Execute(nil) 76 }) 77 78 Context("when checking target fails", func() { 79 BeforeEach(func() { 80 fakeSharedActor.CheckTargetReturns(sharedaction.NotLoggedInError{BinaryName: binaryName}) 81 }) 82 83 It("returns an error", func() { 84 Expect(executeErr).To(MatchError(translatableerror.NotLoggedInError{BinaryName: binaryName})) 85 86 Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1)) 87 _, checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0) 88 Expect(checkTargetedOrg).To(BeTrue()) 89 Expect(checkTargetedSpace).To(BeTrue()) 90 }) 91 }) 92 93 Context("when the user is logged in, and org and space are targeted", func() { 94 BeforeEach(func() { 95 fakeConfig.HasTargetedOrganizationReturns(true) 96 fakeConfig.TargetedOrganizationReturns(configv3.Organization{GUID: "some-org-guid", Name: "some-org"}) 97 fakeConfig.HasTargetedSpaceReturns(true) 98 fakeConfig.TargetedSpaceReturns(configv3.Space{GUID: "some-space-guid", Name: "some-space"}) 99 fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) 100 }) 101 102 Context("when the push settings are valid", func() { 103 var appManifests []manifest.Application 104 105 BeforeEach(func() { 106 appManifests = []manifest.Application{ 107 { 108 Name: appName, 109 Path: pwd, 110 }, 111 } 112 fakeActor.MergeAndValidateSettingsAndManifestsReturns(appManifests, nil) 113 }) 114 115 Context("when the settings can be converted to a valid config", func() { 116 var appConfigs []pushaction.ApplicationConfig 117 118 BeforeEach(func() { 119 appConfigs = []pushaction.ApplicationConfig{ 120 { 121 CurrentApplication: pushaction.Application{Application: v2action.Application{Name: appName, State: ccv2.ApplicationStarted}}, 122 DesiredApplication: pushaction.Application{Application: v2action.Application{Name: appName}}, 123 CurrentRoutes: []v2action.Route{ 124 {Host: "route1", Domain: v2action.Domain{Name: "example.com"}}, 125 {Host: "route2", Domain: v2action.Domain{Name: "example.com"}}, 126 }, 127 DesiredRoutes: []v2action.Route{ 128 {Host: "route3", Domain: v2action.Domain{Name: "example.com"}}, 129 {Host: "route4", Domain: v2action.Domain{Name: "example.com"}}, 130 }, 131 TargetedSpaceGUID: "some-space-guid", 132 Path: pwd, 133 }, 134 } 135 fakeActor.ConvertToApplicationConfigsReturns(appConfigs, pushaction.Warnings{"some-config-warnings"}, nil) 136 }) 137 138 Context("when the apply is successful", func() { 139 var updatedConfig pushaction.ApplicationConfig 140 141 BeforeEach(func() { 142 fakeActor.ApplyStub = func(_ pushaction.ApplicationConfig, _ pushaction.ProgressBar) (<-chan pushaction.ApplicationConfig, <-chan pushaction.Event, <-chan pushaction.Warnings, <-chan error) { 143 configStream := make(chan pushaction.ApplicationConfig, 1) 144 eventStream := make(chan pushaction.Event) 145 warningsStream := make(chan pushaction.Warnings) 146 errorStream := make(chan error) 147 148 updatedConfig = pushaction.ApplicationConfig{ 149 CurrentApplication: pushaction.Application{Application: v2action.Application{Name: appName, GUID: "some-app-guid"}}, 150 DesiredApplication: pushaction.Application{Application: v2action.Application{Name: appName, GUID: "some-app-guid"}}, 151 TargetedSpaceGUID: "some-space-guid", 152 Path: pwd, 153 } 154 155 go func() { 156 defer GinkgoRecover() 157 158 Eventually(eventStream).Should(BeSent(pushaction.SettingUpApplication)) 159 Eventually(eventStream).Should(BeSent(pushaction.CreatedApplication)) 160 Eventually(eventStream).Should(BeSent(pushaction.UpdatedApplication)) 161 Eventually(eventStream).Should(BeSent(pushaction.ConfiguringRoutes)) 162 Eventually(eventStream).Should(BeSent(pushaction.CreatedRoutes)) 163 Eventually(eventStream).Should(BeSent(pushaction.BoundRoutes)) 164 Eventually(eventStream).Should(BeSent(pushaction.ConfiguringServices)) 165 Eventually(eventStream).Should(BeSent(pushaction.BoundServices)) 166 Eventually(eventStream).Should(BeSent(pushaction.ResourceMatching)) 167 Eventually(eventStream).Should(BeSent(pushaction.CreatingArchive)) 168 Eventually(eventStream).Should(BeSent(pushaction.UploadingApplication)) 169 Eventually(fakeProgressBar.ReadyCallCount).Should(Equal(1)) 170 Eventually(eventStream).Should(BeSent(pushaction.RetryUpload)) 171 Eventually(eventStream).Should(BeSent(pushaction.UploadComplete)) 172 Eventually(fakeProgressBar.CompleteCallCount).Should(Equal(1)) 173 Eventually(configStream).Should(BeSent(updatedConfig)) 174 Eventually(eventStream).Should(BeSent(pushaction.Complete)) 175 Eventually(warningsStream).Should(BeSent(pushaction.Warnings{"apply-1", "apply-2"})) 176 close(configStream) 177 close(eventStream) 178 close(warningsStream) 179 close(errorStream) 180 }() 181 182 return configStream, eventStream, warningsStream, errorStream 183 } 184 185 fakeRestartActor.RestartApplicationStub = func(app v2action.Application, client v2action.NOAAClient, config v2action.Config) (<-chan *v2action.LogMessage, <-chan error, <-chan v2action.ApplicationStateChange, <-chan string, <-chan error) { 186 messages := make(chan *v2action.LogMessage) 187 logErrs := make(chan error) 188 appState := make(chan v2action.ApplicationStateChange) 189 warnings := make(chan string) 190 errs := make(chan error) 191 192 go func() { 193 messages <- v2action.NewLogMessage("log message 1", 1, time.Unix(0, 0), "STG", "1") 194 messages <- v2action.NewLogMessage("log message 2", 1, time.Unix(0, 0), "STG", "1") 195 appState <- v2action.ApplicationStateStopping 196 appState <- v2action.ApplicationStateStaging 197 appState <- v2action.ApplicationStateStarting 198 close(messages) 199 close(logErrs) 200 close(appState) 201 close(warnings) 202 close(errs) 203 }() 204 205 return messages, logErrs, appState, warnings, errs 206 } 207 208 applicationSummary := v2action.ApplicationSummary{ 209 Application: v2action.Application{ 210 DetectedBuildpack: types.FilteredString{IsSet: true, Value: "some-buildpack"}, 211 DetectedStartCommand: types.FilteredString{IsSet: true, Value: "some start command"}, 212 GUID: "some-app-guid", 213 Instances: types.NullInt{Value: 3, IsSet: true}, 214 Memory: 128, 215 Name: appName, 216 PackageUpdatedAt: time.Unix(0, 0), 217 State: "STARTED", 218 }, 219 Stack: v2action.Stack{ 220 Name: "potatos", 221 }, 222 Routes: []v2action.Route{ 223 { 224 Host: "banana", 225 Domain: v2action.Domain{ 226 Name: "fruit.com", 227 }, 228 Path: "/hi", 229 }, 230 { 231 Domain: v2action.Domain{ 232 Name: "foobar.com", 233 }, 234 Port: types.NullInt{IsSet: true, Value: 13}, 235 }, 236 }, 237 } 238 warnings := []string{"app-summary-warning"} 239 240 applicationSummary.RunningInstances = []v2action.ApplicationInstanceWithStats{{State: "RUNNING"}} 241 242 fakeRestartActor.GetApplicationSummaryByNameAndSpaceReturns(applicationSummary, warnings, nil) 243 }) 244 245 Context("when no manifest is provided", func() { 246 It("passes through the command line flags", func() { 247 Expect(executeErr).ToNot(HaveOccurred()) 248 249 Expect(fakeActor.MergeAndValidateSettingsAndManifestsCallCount()).To(Equal(1)) 250 cmdSettings, _ := fakeActor.MergeAndValidateSettingsAndManifestsArgsForCall(0) 251 Expect(cmdSettings).To(Equal(pushaction.CommandLineSettings{ 252 Name: appName, 253 CurrentDirectory: pwd, 254 })) 255 }) 256 }) 257 258 Context("when a manifest is provided", func() { 259 var ( 260 tmpDir string 261 pathToManifest string 262 263 originalDir string 264 ) 265 266 BeforeEach(func() { 267 var err error 268 tmpDir, err = ioutil.TempDir("", "v2-push-command-test") 269 Expect(err).ToNot(HaveOccurred()) 270 271 // OS X uses weird symlinks that causes problems for some tests 272 tmpDir, err = filepath.EvalSymlinks(tmpDir) 273 Expect(err).ToNot(HaveOccurred()) 274 275 originalDir, err = os.Getwd() 276 Expect(err).ToNot(HaveOccurred()) 277 278 cmd.OptionalArgs.AppName = "" 279 }) 280 281 AfterEach(func() { 282 Expect(os.Chdir(originalDir)).ToNot(HaveOccurred()) 283 Expect(os.RemoveAll(tmpDir)).ToNot(HaveOccurred()) 284 }) 285 286 Context("via a manfiest.yml in the current directory", func() { 287 var expectedApps []manifest.Application 288 289 BeforeEach(func() { 290 err := os.Chdir(tmpDir) 291 Expect(err).ToNot(HaveOccurred()) 292 293 pathToManifest = filepath.Join(tmpDir, "manifest.yml") 294 err = ioutil.WriteFile(pathToManifest, []byte("some manfiest file"), 0666) 295 Expect(err).ToNot(HaveOccurred()) 296 297 expectedApps = []manifest.Application{{Name: "some-app"}, {Name: "some-other-app"}} 298 fakeActor.ReadManifestReturns(expectedApps, nil) 299 }) 300 301 Context("when reading the manifest file is successful", func() { 302 It("merges app manifest and flags", func() { 303 Expect(executeErr).ToNot(HaveOccurred()) 304 305 Expect(fakeActor.ReadManifestCallCount()).To(Equal(1)) 306 Expect(fakeActor.ReadManifestArgsForCall(0)).To(Equal(pathToManifest)) 307 308 Expect(fakeActor.MergeAndValidateSettingsAndManifestsCallCount()).To(Equal(1)) 309 cmdSettings, manifestApps := fakeActor.MergeAndValidateSettingsAndManifestsArgsForCall(0) 310 Expect(cmdSettings).To(Equal(pushaction.CommandLineSettings{ 311 CurrentDirectory: tmpDir, 312 })) 313 Expect(manifestApps).To(Equal(expectedApps)) 314 }) 315 }) 316 317 Context("when reading manifest file errors", func() { 318 var expectedErr error 319 320 BeforeEach(func() { 321 expectedErr = errors.New("I am an error!!!") 322 323 fakeActor.ReadManifestReturns(nil, expectedErr) 324 }) 325 326 It("returns the error", func() { 327 Expect(executeErr).To(MatchError(expectedErr)) 328 }) 329 }) 330 331 Context("when --no-manifest is specified", func() { 332 BeforeEach(func() { 333 cmd.NoManifest = true 334 }) 335 336 It("ignores the manifest file", func() { 337 Expect(executeErr).ToNot(HaveOccurred()) 338 339 Expect(fakeActor.MergeAndValidateSettingsAndManifestsCallCount()).To(Equal(1)) 340 cmdSettings, manifestApps := fakeActor.MergeAndValidateSettingsAndManifestsArgsForCall(0) 341 Expect(cmdSettings).To(Equal(pushaction.CommandLineSettings{ 342 CurrentDirectory: tmpDir, 343 })) 344 Expect(manifestApps).To(BeNil()) 345 }) 346 }) 347 }) 348 349 Context("via a manfiest.yaml in the current directory", func() { 350 BeforeEach(func() { 351 err := os.Chdir(tmpDir) 352 Expect(err).ToNot(HaveOccurred()) 353 354 pathToManifest = filepath.Join(tmpDir, "manifest.yaml") 355 err = ioutil.WriteFile(pathToManifest, []byte("some manfiest file"), 0666) 356 Expect(err).ToNot(HaveOccurred()) 357 }) 358 359 It("should read the manifest.yml", func() { 360 Expect(executeErr).ToNot(HaveOccurred()) 361 362 Expect(fakeActor.ReadManifestCallCount()).To(Equal(1)) 363 Expect(fakeActor.ReadManifestArgsForCall(0)).To(Equal(pathToManifest)) 364 }) 365 }) 366 367 Context("via the -f flag", func() { 368 BeforeEach(func() { 369 pathToManifest = filepath.Join(tmpDir, "manifest.yaml") 370 err := ioutil.WriteFile(pathToManifest, []byte("some manfiest file"), 0666) 371 Expect(err).ToNot(HaveOccurred()) 372 373 cmd.PathToManifest = flag.PathWithExistenceCheck(pathToManifest) 374 }) 375 376 It("should read the manifest.yml", func() { 377 Expect(executeErr).ToNot(HaveOccurred()) 378 379 Expect(fakeActor.ReadManifestCallCount()).To(Equal(1)) 380 Expect(fakeActor.ReadManifestArgsForCall(0)).To(Equal(pathToManifest)) 381 }) 382 }) 383 }) 384 385 It("converts the manifests to app configs and outputs config warnings", func() { 386 Expect(executeErr).ToNot(HaveOccurred()) 387 388 Expect(testUI.Err).To(Say("some-config-warnings")) 389 390 Expect(fakeActor.ConvertToApplicationConfigsCallCount()).To(Equal(1)) 391 orgGUID, spaceGUID, noStart, manifests := fakeActor.ConvertToApplicationConfigsArgsForCall(0) 392 Expect(orgGUID).To(Equal("some-org-guid")) 393 Expect(spaceGUID).To(Equal("some-space-guid")) 394 Expect(noStart).To(BeFalse()) 395 Expect(manifests).To(Equal(appManifests)) 396 }) 397 398 It("outputs flavor text prior to generating app configuration", func() { 399 Expect(executeErr).ToNot(HaveOccurred()) 400 Expect(testUI.Out).To(Say("Getting app info\\.\\.\\.")) 401 }) 402 403 It("applies each of the application configurations", func() { 404 Expect(executeErr).ToNot(HaveOccurred()) 405 406 Expect(fakeActor.ApplyCallCount()).To(Equal(1)) 407 config, progressBar := fakeActor.ApplyArgsForCall(0) 408 Expect(config).To(Equal(appConfigs[0])) 409 Expect(progressBar).To(Equal(fakeProgressBar)) 410 }) 411 412 It("display diff of changes", func() { 413 Expect(executeErr).ToNot(HaveOccurred()) 414 415 Expect(testUI.Out).To(Say("\\s+name:\\s+%s", appName)) 416 Expect(testUI.Out).To(Say("\\s+path:\\s+%s", regexp.QuoteMeta(appConfigs[0].Path))) 417 Expect(testUI.Out).To(Say("\\s+routes:")) 418 for _, route := range appConfigs[0].CurrentRoutes { 419 Expect(testUI.Out).To(Say(route.String())) 420 } 421 for _, route := range appConfigs[0].DesiredRoutes { 422 Expect(testUI.Out).To(Say(route.String())) 423 } 424 }) 425 426 Context("when the app starts", func() { 427 It("displays app events and warnings", func() { 428 Expect(executeErr).ToNot(HaveOccurred()) 429 430 Expect(testUI.Out).To(Say("Creating app with these attributes\\.\\.\\.")) 431 Expect(testUI.Out).To(Say("Mapping routes\\.\\.\\.")) 432 Expect(testUI.Out).To(Say("Binding services\\.\\.\\.")) 433 Expect(testUI.Out).To(Say("Comparing local files to remote cache\\.\\.\\.")) 434 Expect(testUI.Out).To(Say("Packaging files to upload\\.\\.\\.")) 435 Expect(testUI.Out).To(Say("Uploading files\\.\\.\\.")) 436 Expect(testUI.Out).To(Say("Retrying upload due to an error\\.\\.\\.")) 437 Expect(testUI.Out).To(Say("Waiting for API to complete processing files\\.\\.\\.")) 438 Expect(testUI.Out).To(Say("Stopping app\\.\\.\\.")) 439 440 Expect(testUI.Err).To(Say("some-config-warnings")) 441 Expect(testUI.Err).To(Say("apply-1")) 442 Expect(testUI.Err).To(Say("apply-2")) 443 }) 444 445 It("displays app staging logs", func() { 446 Expect(executeErr).ToNot(HaveOccurred()) 447 448 Expect(testUI.Out).To(Say("log message 1")) 449 Expect(testUI.Out).To(Say("log message 2")) 450 451 Expect(fakeRestartActor.RestartApplicationCallCount()).To(Equal(1)) 452 appConfig, _, _ := fakeRestartActor.RestartApplicationArgsForCall(0) 453 Expect(appConfig).To(Equal(updatedConfig.CurrentApplication.Application)) 454 }) 455 456 It("displays the app summary with isolation segments as well as warnings", func() { 457 Expect(executeErr).ToNot(HaveOccurred()) 458 Expect(testUI.Out).To(Say("name:\\s+%s", appName)) 459 Expect(testUI.Out).To(Say("requested state:\\s+started")) 460 Expect(testUI.Out).To(Say("instances:\\s+1\\/3")) 461 Expect(testUI.Out).To(Say("usage:\\s+128M x 3 instances")) 462 Expect(testUI.Out).To(Say("routes:\\s+banana.fruit.com/hi, foobar.com:13")) 463 Expect(testUI.Out).To(Say("last uploaded:\\s+\\w{3} [0-3]\\d \\w{3} [0-2]\\d:[0-5]\\d:[0-5]\\d \\w+ \\d{4}")) 464 Expect(testUI.Out).To(Say("stack:\\s+potatos")) 465 Expect(testUI.Out).To(Say("buildpack:\\s+some-buildpack")) 466 Expect(testUI.Out).To(Say("start command:\\s+some start command")) 467 468 Expect(testUI.Err).To(Say("app-summary-warning")) 469 }) 470 471 Context("when the start command is explicitly set", func() { 472 BeforeEach(func() { 473 applicationSummary := v2action.ApplicationSummary{ 474 Application: v2action.Application{ 475 Command: types.FilteredString{IsSet: true, Value: "a-different-start-command"}, 476 DetectedBuildpack: types.FilteredString{IsSet: true, Value: "some-buildpack"}, 477 DetectedStartCommand: types.FilteredString{IsSet: true, Value: "some start command"}, 478 GUID: "some-app-guid", 479 Instances: types.NullInt{Value: 3, IsSet: true}, 480 Memory: 128, 481 Name: appName, 482 PackageUpdatedAt: time.Unix(0, 0), 483 State: "STARTED", 484 }, 485 Stack: v2action.Stack{ 486 Name: "potatos", 487 }, 488 Routes: []v2action.Route{ 489 { 490 Host: "banana", 491 Domain: v2action.Domain{ 492 Name: "fruit.com", 493 }, 494 Path: "/hi", 495 }, 496 { 497 Domain: v2action.Domain{ 498 Name: "foobar.com", 499 }, 500 Port: types.NullInt{IsSet: true, Value: 13}, 501 }, 502 }, 503 } 504 warnings := []string{"app-summary-warning"} 505 506 applicationSummary.RunningInstances = []v2action.ApplicationInstanceWithStats{{State: "RUNNING"}} 507 508 fakeRestartActor.GetApplicationSummaryByNameAndSpaceReturns(applicationSummary, warnings, nil) 509 }) 510 511 It("displays the correct start command", func() { 512 Expect(executeErr).ToNot(HaveOccurred()) 513 Expect(testUI.Out).To(Say("name:\\s+%s", appName)) 514 Expect(testUI.Out).To(Say("start command:\\s+a-different-start-command")) 515 }) 516 }) 517 }) 518 519 Context("when no-start is set", func() { 520 BeforeEach(func() { 521 cmd.NoStart = true 522 523 applicationSummary := v2action.ApplicationSummary{ 524 Application: v2action.Application{ 525 Command: types.FilteredString{IsSet: true, Value: "a-different-start-command"}, 526 DetectedBuildpack: types.FilteredString{IsSet: true, Value: "some-buildpack"}, 527 DetectedStartCommand: types.FilteredString{IsSet: true, Value: "some start command"}, 528 GUID: "some-app-guid", 529 Instances: types.NullInt{Value: 3, IsSet: true}, 530 Memory: 128, 531 Name: appName, 532 PackageUpdatedAt: time.Unix(0, 0), 533 State: "STOPPED", 534 }, 535 Stack: v2action.Stack{ 536 Name: "potatos", 537 }, 538 Routes: []v2action.Route{ 539 { 540 Host: "banana", 541 Domain: v2action.Domain{ 542 Name: "fruit.com", 543 }, 544 Path: "/hi", 545 }, 546 { 547 Domain: v2action.Domain{ 548 Name: "foobar.com", 549 }, 550 Port: types.NullInt{IsSet: true, Value: 13}, 551 }, 552 }, 553 } 554 warnings := []string{"app-summary-warning"} 555 556 fakeRestartActor.GetApplicationSummaryByNameAndSpaceReturns(applicationSummary, warnings, nil) 557 }) 558 559 Context("when the app is not running", func() { 560 It("does not start the app", func() { 561 Expect(executeErr).ToNot(HaveOccurred()) 562 Expect(testUI.Out).To(Say("Waiting for API to complete processing files\\.\\.\\.")) 563 Expect(testUI.Out).To(Say("name:\\s+%s", appName)) 564 Expect(testUI.Out).To(Say("requested state:\\s+stopped")) 565 566 Expect(fakeRestartActor.RestartApplicationCallCount()).To(Equal(0)) 567 }) 568 }) 569 }) 570 }) 571 572 Context("when the apply errors", func() { 573 var expectedErr error 574 575 BeforeEach(func() { 576 expectedErr = errors.New("no wayz dude") 577 fakeActor.ApplyStub = func(_ pushaction.ApplicationConfig, _ pushaction.ProgressBar) (<-chan pushaction.ApplicationConfig, <-chan pushaction.Event, <-chan pushaction.Warnings, <-chan error) { 578 configStream := make(chan pushaction.ApplicationConfig) 579 eventStream := make(chan pushaction.Event) 580 warningsStream := make(chan pushaction.Warnings) 581 errorStream := make(chan error) 582 583 go func() { 584 defer GinkgoRecover() 585 586 Eventually(warningsStream).Should(BeSent(pushaction.Warnings{"apply-1", "apply-2"})) 587 Eventually(errorStream).Should(BeSent(expectedErr)) 588 close(configStream) 589 close(eventStream) 590 close(warningsStream) 591 close(errorStream) 592 }() 593 594 return configStream, eventStream, warningsStream, errorStream 595 } 596 }) 597 598 It("outputs the warnings and returns the error", func() { 599 Expect(executeErr).To(MatchError(expectedErr)) 600 601 Expect(testUI.Err).To(Say("some-config-warnings")) 602 Expect(testUI.Err).To(Say("apply-1")) 603 Expect(testUI.Err).To(Say("apply-2")) 604 }) 605 }) 606 }) 607 608 Context("when there is an error converting the app setting into a config", func() { 609 var expectedErr error 610 611 BeforeEach(func() { 612 expectedErr = errors.New("no wayz dude") 613 fakeActor.ConvertToApplicationConfigsReturns(nil, pushaction.Warnings{"some-config-warnings"}, expectedErr) 614 }) 615 616 It("outputs the warnings and returns the error", func() { 617 Expect(executeErr).To(MatchError(expectedErr)) 618 619 Expect(testUI.Err).To(Say("some-config-warnings")) 620 }) 621 }) 622 }) 623 624 Context("when the push settings are invalid", func() { 625 var expectedErr error 626 627 BeforeEach(func() { 628 expectedErr = errors.New("no wayz dude") 629 fakeActor.MergeAndValidateSettingsAndManifestsReturns(nil, expectedErr) 630 }) 631 632 It("returns the error", func() { 633 Expect(executeErr).To(MatchError(expectedErr)) 634 }) 635 }) 636 }) 637 638 Describe("GetCommandLineSettings", func() { 639 var ( 640 settings pushaction.CommandLineSettings 641 executeErr error 642 ) 643 644 JustBeforeEach(func() { 645 settings, executeErr = cmd.GetCommandLineSettings() 646 }) 647 648 Context("when passed app related flags", func() { 649 BeforeEach(func() { 650 cmd.Buildpack = flag.Buildpack{FilteredString: types.FilteredString{Value: "some-buildpack", IsSet: true}} 651 cmd.Command = flag.Command{FilteredString: types.FilteredString{IsSet: true, Value: "echo foo bar baz"}} 652 cmd.DiskQuota = flag.Megabytes{NullUint64: types.NullUint64{Value: 1024, IsSet: true}} 653 cmd.HealthCheckTimeout = 14 654 cmd.HealthCheckType = flag.HealthCheckType{Type: "http"} 655 cmd.Instances = flag.Instances{NullInt: types.NullInt{Value: 12, IsSet: true}} 656 cmd.Memory = flag.Megabytes{NullUint64: types.NullUint64{Value: 100, IsSet: true}} 657 cmd.StackName = "some-stack" 658 }) 659 660 It("sets them on the command line settings", func() { 661 Expect(executeErr).ToNot(HaveOccurred()) 662 Expect(settings.Buildpack).To(Equal(types.FilteredString{Value: "some-buildpack", IsSet: true})) 663 Expect(settings.Command).To(Equal(types.FilteredString{IsSet: true, Value: "echo foo bar baz"})) 664 Expect(settings.DiskQuota).To(Equal(uint64(1024))) 665 Expect(settings.HealthCheckTimeout).To(Equal(14)) 666 Expect(settings.HealthCheckType).To(Equal("http")) 667 Expect(settings.Instances).To(Equal(types.NullInt{Value: 12, IsSet: true})) 668 Expect(settings.Memory).To(Equal(uint64(100))) 669 Expect(settings.StackName).To(Equal("some-stack")) 670 }) 671 }) 672 673 Context("when the -o and -p flags are both given", func() { 674 BeforeEach(func() { 675 cmd.DockerImage.Path = "some-docker-image" 676 cmd.AppPath = "some-directory-path" 677 }) 678 679 It("returns an error", func() { 680 Expect(executeErr).To(MatchError(translatableerror.ArgumentCombinationError{ 681 Args: []string{"--docker-image, -o", "-p"}, 682 })) 683 }) 684 }) 685 686 Context("when only -f and --no-manifest flags are passed", func() { 687 BeforeEach(func() { 688 cmd.PathToManifest = "/some/path.yml" 689 cmd.NoManifest = true 690 }) 691 692 It("returns an ArgumentCombinationError", func() { 693 Expect(executeErr).To(MatchError(translatableerror.ArgumentCombinationError{ 694 Args: []string{"-f", "--no-manifest"}, 695 })) 696 }) 697 }) 698 699 Context("when only -o flag is passed", func() { 700 BeforeEach(func() { 701 cmd.DockerImage.Path = "some-docker-image-path" 702 }) 703 704 It("creates command line setting from command line arguments", func() { 705 Expect(executeErr).ToNot(HaveOccurred()) 706 Expect(settings.Name).To(Equal(appName)) 707 Expect(settings.DockerImage).To(Equal("some-docker-image-path")) 708 }) 709 }) 710 711 Context("when only --docker-username flag are passed", func() { 712 BeforeEach(func() { 713 cmd.DockerUsername = "some-docker-username" 714 }) 715 716 It("returns an error", func() { 717 Expect(executeErr).To(MatchError(translatableerror.RequiredFlagsError{ 718 Arg1: "--docker-image, -o", 719 Arg2: "--docker-username", 720 })) 721 }) 722 }) 723 724 Context("when the -o, --docker-username flags are passed", func() { 725 BeforeEach(func() { 726 cmd.DockerImage.Path = "some-docker-image-path" 727 cmd.DockerUsername = "some-docker-username" 728 }) 729 730 Context("the docker password environment variable is set", func() { 731 BeforeEach(func() { 732 fakeConfig.DockerPasswordReturns("some-docker-password") 733 }) 734 735 It("creates command line setting from command line arguments and config", func() { 736 Expect(executeErr).ToNot(HaveOccurred()) 737 Expect(settings.Name).To(Equal(appName)) 738 Expect(settings.DockerImage).To(Equal("some-docker-image-path")) 739 Expect(settings.DockerUsername).To(Equal("some-docker-username")) 740 Expect(settings.DockerPassword).To(Equal("some-docker-password")) 741 }) 742 }) 743 744 Context("the docker password environment variable is *not* set", func() { 745 It("returns an error", func() { 746 Expect(executeErr).To(MatchError(translatableerror.DockerPasswordNotSetError{})) 747 }) 748 }) 749 }) 750 751 Context("when only -p flag is passed", func() { 752 BeforeEach(func() { 753 cmd.AppPath = "some-directory-path" 754 }) 755 756 It("creates command line setting from command line arguments", func() { 757 Expect(executeErr).ToNot(HaveOccurred()) 758 Expect(settings.Name).To(Equal(appName)) 759 Expect(settings.ProvidedAppPath).To(Equal("some-directory-path")) 760 }) 761 }) 762 763 Context("when -o and -b flags are passed", func() { 764 BeforeEach(func() { 765 cmd.DockerImage.Path = "some-docker-image" 766 cmd.Buildpack = flag.Buildpack{FilteredString: types.FilteredString{Value: "some-buildpack", IsSet: true}} 767 }) 768 769 It("returns an error", func() { 770 Expect(executeErr).To(MatchError(translatableerror.ArgumentCombinationError{ 771 Args: []string{"-b", "--docker-image, -o"}, 772 })) 773 }) 774 }) 775 }) 776 })