github.com/jenspinney/cli@v6.42.1-0.20190207184520-7450c600020e+incompatible/command/v6/push_command_test.go (about) 1 package v6_test 2 3 import ( 4 "errors" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "regexp" 9 "time" 10 11 "code.cloudfoundry.org/cli/actor/actionerror" 12 "code.cloudfoundry.org/cli/actor/pushaction" 13 "code.cloudfoundry.org/cli/actor/v2action" 14 "code.cloudfoundry.org/cli/actor/v2v3action" 15 "code.cloudfoundry.org/cli/actor/v3action" 16 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv2/constant" 17 v3constant "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" 18 "code.cloudfoundry.org/cli/command/commandfakes" 19 "code.cloudfoundry.org/cli/command/flag" 20 "code.cloudfoundry.org/cli/command/translatableerror" 21 . "code.cloudfoundry.org/cli/command/v6" 22 "code.cloudfoundry.org/cli/command/v6/shared/sharedfakes" 23 "code.cloudfoundry.org/cli/command/v6/v6fakes" 24 "code.cloudfoundry.org/cli/types" 25 "code.cloudfoundry.org/cli/util/configv3" 26 "code.cloudfoundry.org/cli/util/manifest" 27 "code.cloudfoundry.org/cli/util/ui" 28 "github.com/cloudfoundry/bosh-cli/director/template" 29 . "github.com/onsi/ginkgo" 30 . "github.com/onsi/ginkgo/extensions/table" 31 . "github.com/onsi/gomega" 32 . "github.com/onsi/gomega/gbytes" 33 ) 34 35 var _ = Describe("push Command", func() { 36 var ( 37 cmd PushCommand 38 testUI *ui.UI 39 fakeConfig *commandfakes.FakeConfig 40 fakeSharedActor *commandfakes.FakeSharedActor 41 fakeActor *v6fakes.FakeV2PushActor 42 fakeRestartActor *v6fakes.FakeRestartActor 43 fakeApplicationSummaryActor *sharedfakes.FakeApplicationSummaryActor 44 fakeProgressBar *v6fakes.FakeProgressBar 45 input *Buffer 46 binaryName string 47 48 appName string 49 executeErr error 50 pwd string 51 ) 52 53 BeforeEach(func() { 54 input = NewBuffer() 55 testUI = ui.NewTestUI(input, NewBuffer(), NewBuffer()) 56 fakeConfig = new(commandfakes.FakeConfig) 57 fakeSharedActor = new(commandfakes.FakeSharedActor) 58 fakeActor = new(v6fakes.FakeV2PushActor) 59 fakeRestartActor = new(v6fakes.FakeRestartActor) 60 fakeApplicationSummaryActor = new(sharedfakes.FakeApplicationSummaryActor) 61 fakeProgressBar = new(v6fakes.FakeProgressBar) 62 63 cmd = PushCommand{ 64 UI: testUI, 65 Config: fakeConfig, 66 SharedActor: fakeSharedActor, 67 Actor: fakeActor, 68 RestartActor: fakeRestartActor, 69 ApplicationSummaryActor: fakeApplicationSummaryActor, 70 ProgressBar: fakeProgressBar, 71 } 72 73 appName = "some-app" 74 cmd.OptionalArgs.AppName = appName 75 binaryName = "faceman" 76 fakeConfig.BinaryNameReturns(binaryName) 77 78 var err error 79 pwd, err = os.Getwd() 80 Expect(err).ToNot(HaveOccurred()) 81 }) 82 83 Context("Execute", func() { 84 JustBeforeEach(func() { 85 executeErr = cmd.Execute(nil) 86 }) 87 88 When("checking target fails", func() { 89 BeforeEach(func() { 90 fakeSharedActor.CheckTargetReturns(actionerror.NotLoggedInError{BinaryName: binaryName}) 91 }) 92 93 It("returns an error", func() { 94 Expect(executeErr).To(MatchError(actionerror.NotLoggedInError{BinaryName: binaryName})) 95 96 Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1)) 97 checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0) 98 Expect(checkTargetedOrg).To(BeTrue()) 99 Expect(checkTargetedSpace).To(BeTrue()) 100 }) 101 }) 102 103 When("the user is logged in, and org and space are targeted", func() { 104 BeforeEach(func() { 105 fakeConfig.HasTargetedOrganizationReturns(true) 106 fakeConfig.TargetedOrganizationReturns(configv3.Organization{GUID: "some-org-guid", Name: "some-org"}) 107 fakeConfig.HasTargetedSpaceReturns(true) 108 fakeConfig.TargetedSpaceReturns(configv3.Space{GUID: "some-space-guid", Name: "some-space"}) 109 fakeConfig.CurrentUserReturns(configv3.User{Name: "some-user"}, nil) 110 }) 111 112 When("the push settings are valid", func() { 113 var appManifests []manifest.Application 114 115 BeforeEach(func() { 116 appManifests = []manifest.Application{ 117 { 118 Name: appName, 119 Path: pwd, 120 }, 121 } 122 fakeActor.MergeAndValidateSettingsAndManifestsReturns(appManifests, nil) 123 }) 124 125 When("the settings can be converted to a valid config", func() { 126 var appConfigs []pushaction.ApplicationConfig 127 128 BeforeEach(func() { 129 appConfigs = []pushaction.ApplicationConfig{ 130 { 131 CurrentApplication: pushaction.Application{Application: v2action.Application{Name: appName, State: constant.ApplicationStarted}}, 132 DesiredApplication: pushaction.Application{Application: v2action.Application{Name: appName}}, 133 CurrentRoutes: []v2action.Route{ 134 {Host: "route1", Domain: v2action.Domain{Name: "example.com"}}, 135 {Host: "route2", Domain: v2action.Domain{Name: "example.com"}}, 136 }, 137 DesiredRoutes: []v2action.Route{ 138 {Host: "route3", Domain: v2action.Domain{Name: "example.com"}}, 139 {Host: "route4", Domain: v2action.Domain{Name: "example.com"}}, 140 }, 141 Path: pwd, 142 }, 143 } 144 fakeActor.ConvertToApplicationConfigsReturns(appConfigs, pushaction.Warnings{"some-config-warnings"}, nil) 145 }) 146 147 When("the apply is successful", func() { 148 var updatedConfig pushaction.ApplicationConfig 149 150 BeforeEach(func() { 151 fakeActor.ApplyStub = func(_ pushaction.ApplicationConfig, _ pushaction.ProgressBar) (<-chan pushaction.ApplicationConfig, <-chan pushaction.Event, <-chan pushaction.Warnings, <-chan error) { 152 configStream := make(chan pushaction.ApplicationConfig, 1) 153 eventStream := make(chan pushaction.Event) 154 warningsStream := make(chan pushaction.Warnings) 155 errorStream := make(chan error) 156 157 updatedConfig = pushaction.ApplicationConfig{ 158 CurrentApplication: pushaction.Application{Application: v2action.Application{Name: appName, GUID: "some-app-guid"}}, 159 DesiredApplication: pushaction.Application{Application: v2action.Application{Name: appName, GUID: "some-app-guid"}}, 160 Path: pwd, 161 } 162 163 go func() { 164 defer GinkgoRecover() 165 166 Eventually(eventStream).Should(BeSent(pushaction.SettingUpApplication)) 167 Eventually(eventStream).Should(BeSent(pushaction.CreatedApplication)) 168 Eventually(eventStream).Should(BeSent(pushaction.UpdatedApplication)) 169 Eventually(eventStream).Should(BeSent(pushaction.CreatingAndMappingRoutes)) 170 Eventually(eventStream).Should(BeSent(pushaction.CreatedRoutes)) 171 Eventually(eventStream).Should(BeSent(pushaction.BoundRoutes)) 172 Eventually(eventStream).Should(BeSent(pushaction.UnmappingRoutes)) 173 Eventually(eventStream).Should(BeSent(pushaction.ConfiguringServices)) 174 Eventually(eventStream).Should(BeSent(pushaction.BoundServices)) 175 Eventually(eventStream).Should(BeSent(pushaction.ResourceMatching)) 176 Eventually(eventStream).Should(BeSent(pushaction.UploadingApplication)) 177 Eventually(eventStream).Should(BeSent(pushaction.CreatingArchive)) 178 Eventually(eventStream).Should(BeSent(pushaction.UploadingApplicationWithArchive)) 179 Eventually(fakeProgressBar.ReadyCallCount).Should(Equal(1)) 180 Eventually(eventStream).Should(BeSent(pushaction.RetryUpload)) 181 Eventually(eventStream).Should(BeSent(pushaction.UploadWithArchiveComplete)) 182 Eventually(fakeProgressBar.CompleteCallCount).Should(Equal(1)) 183 Eventually(configStream).Should(BeSent(updatedConfig)) 184 Eventually(eventStream).Should(BeSent(pushaction.Complete)) 185 Eventually(warningsStream).Should(BeSent(pushaction.Warnings{"apply-1", "apply-2"})) 186 close(configStream) 187 close(eventStream) 188 close(warningsStream) 189 close(errorStream) 190 }() 191 192 return configStream, eventStream, warningsStream, errorStream 193 } 194 195 fakeRestartActor.RestartApplicationStub = func(app v2action.Application, client v2action.NOAAClient) (<-chan *v2action.LogMessage, <-chan error, <-chan v2action.ApplicationStateChange, <-chan string, <-chan error) { 196 messages := make(chan *v2action.LogMessage) 197 logErrs := make(chan error) 198 appState := make(chan v2action.ApplicationStateChange) 199 warnings := make(chan string) 200 errs := make(chan error) 201 202 go func() { 203 messages <- v2action.NewLogMessage("log message 1", 1, time.Unix(0, 0), "STG", "1") 204 messages <- v2action.NewLogMessage("log message 2", 1, time.Unix(0, 0), "STG", "1") 205 appState <- v2action.ApplicationStateStopping 206 appState <- v2action.ApplicationStateStaging 207 appState <- v2action.ApplicationStateStarting 208 close(messages) 209 close(logErrs) 210 close(appState) 211 close(warnings) 212 close(errs) 213 }() 214 215 return messages, logErrs, appState, warnings, errs 216 } 217 218 applicationSummary := v2action.ApplicationSummary{ 219 Application: v2action.Application{ 220 DetectedBuildpack: types.FilteredString{IsSet: true, Value: "some-buildpack"}, 221 DetectedStartCommand: types.FilteredString{IsSet: true, Value: "some start command"}, 222 GUID: "some-app-guid", 223 Instances: types.NullInt{Value: 3, IsSet: true}, 224 Memory: types.NullByteSizeInMb{IsSet: true, Value: 128}, 225 Name: appName, 226 PackageUpdatedAt: time.Unix(0, 0), 227 State: "STARTED", 228 }, 229 Stack: v2action.Stack{ 230 Name: "potatos", 231 }, 232 Routes: []v2action.Route{ 233 { 234 Host: "banana", 235 Domain: v2action.Domain{ 236 Name: "fruit.com", 237 }, 238 Path: "/hi", 239 }, 240 { 241 Domain: v2action.Domain{ 242 Name: "foobar.com", 243 }, 244 Port: types.NullInt{IsSet: true, Value: 13}, 245 }, 246 }, 247 } 248 warnings := []string{"app-summary-warning"} 249 250 applicationSummary.RunningInstances = []v2action.ApplicationInstanceWithStats{{State: "RUNNING"}} 251 252 fakeRestartActor.GetApplicationSummaryByNameAndSpaceReturns(applicationSummary, warnings, nil) 253 }) 254 255 When("no manifest is provided", func() { 256 It("passes through the command line flags", func() { 257 Expect(executeErr).ToNot(HaveOccurred()) 258 259 Expect(fakeActor.MergeAndValidateSettingsAndManifestsCallCount()).To(Equal(1)) 260 cmdSettings, _ := fakeActor.MergeAndValidateSettingsAndManifestsArgsForCall(0) 261 Expect(cmdSettings).To(Equal(pushaction.CommandLineSettings{ 262 Name: appName, 263 CurrentDirectory: pwd, 264 })) 265 }) 266 }) 267 268 When("a manifest is provided", func() { 269 var ( 270 tmpDir string 271 providedPath string 272 273 originalDir string 274 ) 275 276 BeforeEach(func() { 277 var err error 278 tmpDir, err = ioutil.TempDir("", "push-command-test") 279 Expect(err).ToNot(HaveOccurred()) 280 281 // OS X uses weird symlinks that causes problems for some tests 282 tmpDir, err = filepath.EvalSymlinks(tmpDir) 283 Expect(err).ToNot(HaveOccurred()) 284 285 originalDir, err = os.Getwd() 286 Expect(err).ToNot(HaveOccurred()) 287 288 cmd.OptionalArgs.AppName = "" 289 }) 290 291 AfterEach(func() { 292 Expect(os.Chdir(originalDir)).ToNot(HaveOccurred()) 293 Expect(os.RemoveAll(tmpDir)).ToNot(HaveOccurred()) 294 }) 295 296 Context("via a manifest.yml in the current directory", func() { 297 var expectedApps []manifest.Application 298 299 BeforeEach(func() { 300 err := os.Chdir(tmpDir) 301 Expect(err).ToNot(HaveOccurred()) 302 303 providedPath = filepath.Join(tmpDir, "manifest.yml") 304 err = ioutil.WriteFile(providedPath, []byte("some manifest file"), 0666) 305 Expect(err).ToNot(HaveOccurred()) 306 307 expectedApps = []manifest.Application{{Name: "some-app"}, {Name: "some-other-app"}} 308 fakeActor.ReadManifestReturns(expectedApps, nil, nil) 309 }) 310 311 When("reading the manifest file is successful", func() { 312 It("merges app manifest and flags", func() { 313 Expect(executeErr).ToNot(HaveOccurred()) 314 315 Expect(fakeActor.ReadManifestCallCount()).To(Equal(1)) 316 Expect(fakeActor.ReadManifestArgsForCall(0)).To(Equal(providedPath)) 317 318 Expect(fakeActor.MergeAndValidateSettingsAndManifestsCallCount()).To(Equal(1)) 319 cmdSettings, manifestApps := fakeActor.MergeAndValidateSettingsAndManifestsArgsForCall(0) 320 Expect(cmdSettings).To(Equal(pushaction.CommandLineSettings{ 321 CurrentDirectory: tmpDir, 322 })) 323 Expect(manifestApps).To(Equal(expectedApps)) 324 }) 325 326 It("outputs corresponding flavor text", func() { 327 Expect(executeErr).ToNot(HaveOccurred()) 328 329 Expect(testUI.Out).To(Say(`Pushing from manifest to org some-org / space some-space as some-user\.\.\.`)) 330 Expect(testUI.Out).To(Say("Using manifest file %s", regexp.QuoteMeta(providedPath))) 331 }) 332 }) 333 334 When("reading manifest file errors", func() { 335 var expectedErr error 336 337 BeforeEach(func() { 338 expectedErr = errors.New("I am an error!!!") 339 340 fakeActor.ReadManifestReturns(nil, nil, expectedErr) 341 }) 342 343 It("returns the error", func() { 344 Expect(executeErr).To(MatchError(expectedErr)) 345 }) 346 }) 347 348 When("--no-manifest is specified", func() { 349 BeforeEach(func() { 350 cmd.NoManifest = true 351 }) 352 353 It("ignores the manifest file", func() { 354 Expect(executeErr).ToNot(HaveOccurred()) 355 356 Expect(fakeActor.MergeAndValidateSettingsAndManifestsCallCount()).To(Equal(1)) 357 cmdSettings, manifestApps := fakeActor.MergeAndValidateSettingsAndManifestsArgsForCall(0) 358 Expect(cmdSettings).To(Equal(pushaction.CommandLineSettings{ 359 CurrentDirectory: tmpDir, 360 })) 361 Expect(manifestApps).To(BeNil()) 362 }) 363 }) 364 }) 365 366 Context("via a manifest.yaml in the current directory", func() { 367 BeforeEach(func() { 368 err := os.Chdir(tmpDir) 369 Expect(err).ToNot(HaveOccurred()) 370 371 providedPath = filepath.Join(tmpDir, "manifest.yaml") 372 err = ioutil.WriteFile(providedPath, []byte("some manifest file"), 0666) 373 Expect(err).ToNot(HaveOccurred()) 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(providedPath)) 381 }) 382 }) 383 384 Context("via the -f flag", func() { 385 Context("given a path with filename 'manifest.yml'", func() { 386 BeforeEach(func() { 387 providedPath = filepath.Join(tmpDir, "manifest.yml") 388 }) 389 390 When("the manifest.yml file does not exist", func() { 391 BeforeEach(func() { 392 cmd.PathToManifest = flag.PathWithExistenceCheck(providedPath) 393 }) 394 395 It("returns an error", func() { 396 Expect(os.IsNotExist(executeErr)).To(BeTrue()) 397 398 Expect(testUI.Out).ToNot(Say("Pushing from manifest")) 399 Expect(testUI.Out).ToNot(Say("Using manifest file")) 400 401 Expect(fakeActor.ReadManifestCallCount()).To(Equal(0)) 402 }) 403 }) 404 405 When("the manifest.yml file exists", func() { 406 BeforeEach(func() { 407 err := ioutil.WriteFile(providedPath, []byte(`key: "value"`), 0666) 408 Expect(err).ToNot(HaveOccurred()) 409 410 cmd.PathToManifest = flag.PathWithExistenceCheck(providedPath) 411 }) 412 413 It("should read the manifest.yml file and outputs corresponding flavor text", func() { 414 Expect(executeErr).ToNot(HaveOccurred()) 415 416 Expect(testUI.Out).To(Say(`Pushing from manifest to org some-org / space some-space as some-user\.\.\.`)) 417 Expect(testUI.Out).To(Say("Using manifest file %s", regexp.QuoteMeta(providedPath))) 418 419 Expect(fakeActor.ReadManifestCallCount()).To(Equal(1)) 420 Expect(fakeActor.ReadManifestArgsForCall(0)).To(Equal(providedPath)) 421 }) 422 423 Context("variable interpolation", func() { 424 Context("vars file only", func() { 425 When("a vars file is also provided", func() { 426 var providedVarsFilePath string 427 428 BeforeEach(func() { 429 providedVarsFilePath = filepath.Join(tmpDir, "vars-file.yml") 430 cmd.VarsFilePaths = []flag.PathWithExistenceCheck{flag.PathWithExistenceCheck(providedVarsFilePath)} 431 }) 432 433 It("should read the vars-file.yml file and replace the variables in the manifest.yml file", func() { 434 Expect(executeErr).ToNot(HaveOccurred()) 435 436 Expect(testUI.Out).To(Say(`Pushing from manifest to org some-org / space some-space as some-user\.\.\.`)) 437 Expect(testUI.Out).To(Say("Using manifest file %s", regexp.QuoteMeta(providedPath))) 438 439 Expect(fakeActor.ReadManifestCallCount()).To(Equal(1)) 440 manifest, varsFiles, vars := fakeActor.ReadManifestArgsForCall(0) 441 Expect(manifest).To(Equal(providedPath)) 442 Expect(varsFiles).To(Equal([]string{providedVarsFilePath})) 443 Expect(vars).To(BeEmpty()) 444 }) 445 }) 446 447 When("multiple vars files are provided", func() { 448 var ( 449 firstProvidedVarsFilePath string 450 secondProvidedVarsFilePath string 451 ) 452 453 BeforeEach(func() { 454 firstProvidedVarsFilePath = filepath.Join(tmpDir, "vars-file-1.yml") 455 firstVarsFile := flag.PathWithExistenceCheck(firstProvidedVarsFilePath) 456 457 secondProvidedVarsFilePath = filepath.Join(tmpDir, "vars-file-2.yml") 458 secondVarsFile := flag.PathWithExistenceCheck(secondProvidedVarsFilePath) 459 cmd.VarsFilePaths = []flag.PathWithExistenceCheck{firstVarsFile, secondVarsFile} 460 }) 461 462 It("should read the vars-file.yml file and replace the variables in the manifest.yml file", func() { 463 Expect(executeErr).ToNot(HaveOccurred()) 464 465 Expect(testUI.Out).To(Say(`Pushing from manifest to org some-org / space some-space as some-user\.\.\.`)) 466 Expect(testUI.Out).To(Say("Using manifest file %s", regexp.QuoteMeta(providedPath))) 467 468 Expect(fakeActor.ReadManifestCallCount()).To(Equal(1)) 469 manifest, varsFiles, vars := fakeActor.ReadManifestArgsForCall(0) 470 Expect(manifest).To(Equal(providedPath)) 471 Expect(varsFiles).To(Equal([]string{firstProvidedVarsFilePath, secondProvidedVarsFilePath})) 472 Expect(vars).To(BeEmpty()) 473 }) 474 }) 475 }) 476 477 Context("vars flag only", func() { 478 var vars []template.VarKV 479 480 BeforeEach(func() { 481 vars = []template.VarKV{ 482 {Name: "some-var", Value: "some-value"}, 483 {Name: "another-var", Value: 1}, 484 } 485 486 cmd.Vars = vars 487 }) 488 489 It("should read the vars and pass only the vars array to ReadManifest", func() { 490 Expect(executeErr).ToNot(HaveOccurred()) 491 492 Expect(testUI.Out).To(Say(`Pushing from manifest to org some-org / space some-space as some-user\.\.\.`)) 493 Expect(testUI.Out).To(Say("Using manifest file %s", regexp.QuoteMeta(providedPath))) 494 495 Expect(fakeActor.ReadManifestCallCount()).To(Equal(1)) 496 manifest, varsFiles, vars := fakeActor.ReadManifestArgsForCall(0) 497 Expect(manifest).To(Equal(providedPath)) 498 Expect(varsFiles).To(BeEmpty()) 499 Expect(vars).To(ConsistOf([]template.VarKV{ 500 {Name: "some-var", Value: "some-value"}, 501 {Name: "another-var", Value: 1}, 502 })) 503 }) 504 }) 505 }) 506 }) 507 }) 508 509 Context("given a path that is a directory", func() { 510 511 var ( 512 ymlFile string 513 yamlFile string 514 ) 515 516 BeforeEach(func() { 517 providedPath = tmpDir 518 cmd.PathToManifest = flag.PathWithExistenceCheck(providedPath) 519 }) 520 521 When("the directory does not contain a 'manifest.y{a}ml' file", func() { 522 It("returns an error", func() { 523 Expect(executeErr).To(MatchError(translatableerror.ManifestFileNotFoundInDirectoryError{PathToManifest: providedPath})) 524 Expect(testUI.Out).ToNot(Say("Pushing from manifest")) 525 Expect(testUI.Out).ToNot(Say("Using manifest file")) 526 527 Expect(fakeActor.ReadManifestCallCount()).To(Equal(0)) 528 }) 529 }) 530 531 When("the directory contains a 'manifest.yml' file", func() { 532 BeforeEach(func() { 533 ymlFile = filepath.Join(providedPath, "manifest.yml") 534 err := ioutil.WriteFile(ymlFile, []byte(`key: "value"`), 0666) 535 Expect(err).ToNot(HaveOccurred()) 536 }) 537 538 It("should read the manifest.yml file and outputs corresponding flavor text", func() { 539 Expect(executeErr).ToNot(HaveOccurred()) 540 541 Expect(testUI.Out).To(Say(`Pushing from manifest to org some-org / space some-space as some-user\.\.\.`)) 542 Expect(testUI.Out).To(Say("Using manifest file %s", regexp.QuoteMeta(ymlFile))) 543 544 Expect(fakeActor.ReadManifestCallCount()).To(Equal(1)) 545 Expect(fakeActor.ReadManifestArgsForCall(0)).To(Equal(ymlFile)) 546 }) 547 }) 548 549 When("the directory contains a 'manifest.yaml' file", func() { 550 BeforeEach(func() { 551 yamlFile = filepath.Join(providedPath, "manifest.yaml") 552 err := ioutil.WriteFile(yamlFile, []byte(`key: "value"`), 0666) 553 Expect(err).ToNot(HaveOccurred()) 554 }) 555 556 It("should read the manifest.yaml file and outputs corresponding flavor text", func() { 557 Expect(executeErr).ToNot(HaveOccurred()) 558 559 Expect(testUI.Out).To(Say(`Pushing from manifest to org some-org / space some-space as some-user\.\.\.`)) 560 Expect(testUI.Out).To(Say("Using manifest file %s", regexp.QuoteMeta(yamlFile))) 561 562 Expect(fakeActor.ReadManifestCallCount()).To(Equal(1)) 563 Expect(fakeActor.ReadManifestArgsForCall(0)).To(Equal(yamlFile)) 564 }) 565 }) 566 567 When("the directory contains both a 'manifest.yml' and 'manifest.yaml' file", func() { 568 BeforeEach(func() { 569 ymlFile = filepath.Join(providedPath, "manifest.yml") 570 err := ioutil.WriteFile(ymlFile, []byte(`key: "value"`), 0666) 571 Expect(err).ToNot(HaveOccurred()) 572 573 yamlFile = filepath.Join(providedPath, "manifest.yaml") 574 err = ioutil.WriteFile(yamlFile, []byte(`key: "value"`), 0666) 575 Expect(err).ToNot(HaveOccurred()) 576 }) 577 578 It("should read the manifest.yml file and outputs corresponding flavor text", func() { 579 Expect(executeErr).ToNot(HaveOccurred()) 580 581 Expect(testUI.Out).To(Say(`Pushing from manifest to org some-org / space some-space as some-user\.\.\.`)) 582 Expect(testUI.Out).To(Say("Using manifest file %s", regexp.QuoteMeta(ymlFile))) 583 584 Expect(fakeActor.ReadManifestCallCount()).To(Equal(1)) 585 Expect(fakeActor.ReadManifestArgsForCall(0)).To(Equal(ymlFile)) 586 }) 587 }) 588 }) 589 }) 590 }) 591 592 When("an app name and manifest are provided", func() { 593 var ( 594 tmpDir string 595 pathToManifest string 596 597 originalDir string 598 ) 599 600 BeforeEach(func() { 601 var err error 602 tmpDir, err = ioutil.TempDir("", "push-command-test") 603 Expect(err).ToNot(HaveOccurred()) 604 605 // OS X uses weird symlinks that causes problems for some tests 606 tmpDir, err = filepath.EvalSymlinks(tmpDir) 607 Expect(err).ToNot(HaveOccurred()) 608 609 pathToManifest = filepath.Join(tmpDir, "manifest.yml") 610 err = ioutil.WriteFile(pathToManifest, []byte("some manfiest file"), 0666) 611 Expect(err).ToNot(HaveOccurred()) 612 613 originalDir, err = os.Getwd() 614 Expect(err).ToNot(HaveOccurred()) 615 616 err = os.Chdir(tmpDir) 617 Expect(err).ToNot(HaveOccurred()) 618 }) 619 620 AfterEach(func() { 621 Expect(os.Chdir(originalDir)).ToNot(HaveOccurred()) 622 Expect(os.RemoveAll(tmpDir)).ToNot(HaveOccurred()) 623 }) 624 625 It("outputs corresponding flavor text", func() { 626 Expect(executeErr).ToNot(HaveOccurred()) 627 628 Expect(testUI.Out).To(Say(`Pushing from manifest to org some-org / space some-space as some-user\.\.\.`)) 629 Expect(testUI.Out).To(Say("Using manifest file %s", regexp.QuoteMeta(pathToManifest))) 630 }) 631 }) 632 633 It("converts the manifests to app configs and outputs config warnings", func() { 634 Expect(executeErr).ToNot(HaveOccurred()) 635 636 Expect(testUI.Err).To(Say("some-config-warnings")) 637 638 Expect(fakeActor.ConvertToApplicationConfigsCallCount()).To(Equal(1)) 639 orgGUID, spaceGUID, noStart, manifests := fakeActor.ConvertToApplicationConfigsArgsForCall(0) 640 Expect(orgGUID).To(Equal("some-org-guid")) 641 Expect(spaceGUID).To(Equal("some-space-guid")) 642 Expect(noStart).To(BeFalse()) 643 Expect(manifests).To(Equal(appManifests)) 644 }) 645 646 It("outputs flavor text prior to generating app configuration", func() { 647 Expect(executeErr).ToNot(HaveOccurred()) 648 Expect(testUI.Out).To(Say("Pushing app %s to org some-org / space some-space as some-user", appName)) 649 Expect(testUI.Out).To(Say(`Getting app info\.\.\.`)) 650 }) 651 652 It("applies each of the application configurations", func() { 653 Expect(executeErr).ToNot(HaveOccurred()) 654 655 Expect(fakeActor.ApplyCallCount()).To(Equal(1)) 656 config, progressBar := fakeActor.ApplyArgsForCall(0) 657 Expect(config).To(Equal(appConfigs[0])) 658 Expect(progressBar).To(Equal(fakeProgressBar)) 659 }) 660 661 It("display diff of changes", func() { 662 Expect(executeErr).ToNot(HaveOccurred()) 663 664 Expect(testUI.Out).To(Say(`\s+name:\s+%s`, appName)) 665 Expect(testUI.Out).To(Say(`\s+path:\s+%s`, regexp.QuoteMeta(appConfigs[0].Path))) 666 Expect(testUI.Out).To(Say(`\s+routes:`)) 667 for _, route := range appConfigs[0].CurrentRoutes { 668 Expect(testUI.Out).To(Say(route.String())) 669 } 670 for _, route := range appConfigs[0].DesiredRoutes { 671 Expect(testUI.Out).To(Say(route.String())) 672 } 673 }) 674 675 When("the app starts", func() { 676 It("displays app events and warnings", func() { 677 Expect(executeErr).ToNot(HaveOccurred()) 678 679 Expect(testUI.Out).To(Say(`Creating app with these attributes\.\.\.`)) 680 Expect(testUI.Out).To(Say(`Mapping routes\.\.\.`)) 681 Expect(testUI.Out).To(Say(`Unmapping routes\.\.\.`)) 682 Expect(testUI.Out).To(Say(`Binding services\.\.\.`)) 683 Expect(testUI.Out).To(Say(`Comparing local files to remote cache\.\.\.`)) 684 Expect(testUI.Out).To(Say("All files found in remote cache; nothing to upload.")) 685 Expect(testUI.Out).To(Say(`Waiting for API to complete processing files\.\.\.`)) 686 Expect(testUI.Out).To(Say(`Packaging files to upload\.\.\.`)) 687 Expect(testUI.Out).To(Say(`Uploading files\.\.\.`)) 688 Expect(testUI.Out).To(Say(`Retrying upload due to an error\.\.\.`)) 689 Expect(testUI.Out).To(Say(`Waiting for API to complete processing files\.\.\.`)) 690 Expect(testUI.Out).To(Say(`Stopping app\.\.\.`)) 691 692 Expect(testUI.Err).To(Say("some-config-warnings")) 693 Expect(testUI.Err).To(Say("apply-1")) 694 Expect(testUI.Err).To(Say("apply-2")) 695 }) 696 697 It("displays app staging logs", func() { 698 Expect(executeErr).ToNot(HaveOccurred()) 699 700 Expect(testUI.Out).To(Say("log message 1")) 701 Expect(testUI.Out).To(Say("log message 2")) 702 703 Expect(fakeRestartActor.RestartApplicationCallCount()).To(Equal(1)) 704 appConfig, _ := fakeRestartActor.RestartApplicationArgsForCall(0) 705 Expect(appConfig).To(Equal(updatedConfig.CurrentApplication.Application)) 706 }) 707 708 Context("Process Information", func() { 709 BeforeEach(func() { 710 fakeApplicationSummaryActor.GetApplicationSummaryByNameAndSpaceReturns( 711 v2v3action.ApplicationSummary{ 712 ApplicationSummary: v3action.ApplicationSummary{ 713 Application: v3action.Application{ 714 Name: appName, 715 }, 716 ProcessSummaries: v3action.ProcessSummaries{ 717 { 718 Process: v3action.Process{ 719 Type: "aba", 720 Command: *types.NewFilteredString("some-command-1"), 721 MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, 722 DiskInMB: types.NullUint64{Value: 1024, IsSet: true}, 723 }, 724 }, 725 { 726 Process: v3action.Process{ 727 Type: "console", 728 Command: *types.NewFilteredString("some-command-2"), 729 MemoryInMB: types.NullUint64{Value: 16, IsSet: true}, 730 DiskInMB: types.NullUint64{Value: 512, IsSet: true}, 731 }, 732 }, 733 }, 734 }, 735 }, 736 v2v3action.Warnings{"combo-summary-warning"}, 737 nil) 738 }) 739 740 It("displays process information", func() { 741 Expect(executeErr).ToNot(HaveOccurred()) 742 743 Expect(testUI.Out).To(Say(`name:\s+%s`, appName)) 744 Expect(testUI.Out).To(Say(`type:\s+aba`)) 745 Expect(testUI.Out).To(Say(`instances:\s+0/0`)) 746 Expect(testUI.Out).To(Say(`memory usage:\s+32M`)) 747 Expect(testUI.Out).To(Say(`start command:\s+some-command-1`)) 748 Expect(testUI.Out).To(Say(`type:\s+console`)) 749 Expect(testUI.Out).To(Say(`instances:\s+0/0`)) 750 Expect(testUI.Out).To(Say(`memory usage:\s+16M`)) 751 Expect(testUI.Out).To(Say(`start command:\s+some-command-2`)) 752 753 Expect(testUI.Err).To(Say("combo-summary-warning")) 754 755 Expect(fakeApplicationSummaryActor.GetApplicationSummaryByNameAndSpaceCallCount()).To(Equal(1)) 756 passedAppName, spaceGUID, withObfuscatedValues := fakeApplicationSummaryActor.GetApplicationSummaryByNameAndSpaceArgsForCall(0) 757 Expect(passedAppName).To(Equal(appName)) 758 Expect(spaceGUID).To(Equal("some-space-guid")) 759 Expect(withObfuscatedValues).To(BeTrue()) 760 }) 761 }) 762 763 When("the start command is explicitly set", func() { 764 BeforeEach(func() { 765 v3ApplicationSummary := v3action.ApplicationSummary{ 766 Application: v3action.Application{ 767 Name: appName, 768 }, 769 ProcessSummaries: v3action.ProcessSummaries{ 770 { 771 Process: v3action.Process{ 772 Type: "aba", 773 Command: *types.NewFilteredString("a-different-start-command"), 774 MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, 775 DiskInMB: types.NullUint64{Value: 1024, IsSet: true}, 776 }, 777 InstanceDetails: []v3action.ProcessInstance{ 778 v3action.ProcessInstance{ 779 State: v3constant.ProcessInstanceRunning, 780 }, 781 }, 782 }, 783 }, 784 } 785 786 warnings := []string{"app-summary-warning"} 787 applicationSummary := v2v3action.ApplicationSummary{ 788 ApplicationSummary: v3ApplicationSummary, 789 } 790 791 fakeApplicationSummaryActor.GetApplicationSummaryByNameAndSpaceReturns(applicationSummary, warnings, nil) 792 }) 793 794 It("displays the correct start command", func() { 795 Expect(executeErr).ToNot(HaveOccurred()) 796 Expect(testUI.Out).To(Say(`name:\s+%s`, appName)) 797 Expect(testUI.Out).To(Say(`start command:\s+a-different-start-command`)) 798 }) 799 }) 800 }) 801 802 When("no-start is set", func() { 803 BeforeEach(func() { 804 cmd.NoStart = true 805 v3ApplicationSummary := v3action.ApplicationSummary{ 806 Application: v3action.Application{ 807 Name: appName, 808 State: v3constant.ApplicationStopped, 809 }, 810 ProcessSummaries: v3action.ProcessSummaries{ 811 { 812 Process: v3action.Process{ 813 Type: "aba", 814 Command: *types.NewFilteredString("a-different-start-command"), 815 MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, 816 DiskInMB: types.NullUint64{Value: 1024, IsSet: true}, 817 }, 818 InstanceDetails: []v3action.ProcessInstance{}, 819 }, 820 }, 821 } 822 823 warnings := []string{"app-summary-warning"} 824 applicationSummary := v2v3action.ApplicationSummary{ 825 ApplicationSummary: v3ApplicationSummary, 826 } 827 828 fakeApplicationSummaryActor.GetApplicationSummaryByNameAndSpaceReturns(applicationSummary, warnings, nil) 829 }) 830 831 When("the app is not running", func() { 832 It("does not start the app", func() { 833 Expect(executeErr).ToNot(HaveOccurred()) 834 Expect(testUI.Out).To(Say(`Waiting for API to complete processing files\.\.\.`)) 835 Expect(testUI.Out).To(Say(`name:\s+%s`, appName)) 836 Expect(testUI.Out).To(Say(`requested state:\s+stopped`)) 837 838 Expect(fakeRestartActor.RestartApplicationCallCount()).To(Equal(0)) 839 }) 840 }) 841 }) 842 }) 843 844 When("the apply errors", func() { 845 var expectedErr error 846 847 BeforeEach(func() { 848 expectedErr = errors.New("no wayz dude") 849 fakeActor.ApplyStub = func(_ pushaction.ApplicationConfig, _ pushaction.ProgressBar) (<-chan pushaction.ApplicationConfig, <-chan pushaction.Event, <-chan pushaction.Warnings, <-chan error) { 850 configStream := make(chan pushaction.ApplicationConfig) 851 eventStream := make(chan pushaction.Event) 852 warningsStream := make(chan pushaction.Warnings) 853 errorStream := make(chan error) 854 855 go func() { 856 defer GinkgoRecover() 857 858 Eventually(warningsStream).Should(BeSent(pushaction.Warnings{"apply-1", "apply-2"})) 859 Eventually(errorStream).Should(BeSent(expectedErr)) 860 close(configStream) 861 close(eventStream) 862 close(warningsStream) 863 close(errorStream) 864 }() 865 866 return configStream, eventStream, warningsStream, errorStream 867 } 868 }) 869 870 It("outputs the warnings and returns the error", func() { 871 Expect(executeErr).To(MatchError(expectedErr)) 872 873 Expect(testUI.Err).To(Say("some-config-warnings")) 874 Expect(testUI.Err).To(Say("apply-1")) 875 Expect(testUI.Err).To(Say("apply-2")) 876 }) 877 }) 878 }) 879 880 When("there is an error converting the app setting into a config", func() { 881 var expectedErr error 882 883 BeforeEach(func() { 884 expectedErr = errors.New("no wayz dude") 885 fakeActor.ConvertToApplicationConfigsReturns(nil, pushaction.Warnings{"some-config-warnings"}, expectedErr) 886 }) 887 888 It("outputs the warnings and returns the error", func() { 889 Expect(executeErr).To(MatchError(expectedErr)) 890 891 Expect(testUI.Err).To(Say("some-config-warnings")) 892 }) 893 }) 894 }) 895 896 When("the push settings are invalid", func() { 897 var expectedErr error 898 899 BeforeEach(func() { 900 expectedErr = errors.New("no wayz dude") 901 fakeActor.MergeAndValidateSettingsAndManifestsReturns(nil, expectedErr) 902 }) 903 904 It("returns the error", func() { 905 Expect(executeErr).To(MatchError(expectedErr)) 906 }) 907 }) 908 }) 909 }) 910 911 Describe("GetCommandLineSettings", func() { 912 Context("valid flag combinations", func() { 913 var ( 914 settings pushaction.CommandLineSettings 915 commandLineSettingsErr error 916 ) 917 918 JustBeforeEach(func() { 919 settings, commandLineSettingsErr = cmd.GetCommandLineSettings() 920 Expect(commandLineSettingsErr).ToNot(HaveOccurred()) 921 }) 922 923 When("general app settings are given", func() { 924 BeforeEach(func() { 925 cmd.Buildpacks = []string{"some-buildpack"} 926 cmd.Command = flag.Command{FilteredString: types.FilteredString{IsSet: true, Value: "echo foo bar baz"}} 927 cmd.DiskQuota = flag.Megabytes{NullUint64: types.NullUint64{Value: 1024, IsSet: true}} 928 cmd.HealthCheckTimeout = 14 929 cmd.HealthCheckType = flag.HealthCheckTypeWithDeprecatedValue{Type: "http"} 930 cmd.Instances = flag.Instances{NullInt: types.NullInt{Value: 12, IsSet: true}} 931 cmd.Memory = flag.Megabytes{NullUint64: types.NullUint64{Value: 100, IsSet: true}} 932 cmd.StackName = "some-stack" 933 }) 934 935 It("sets them on the command line settings", func() { 936 Expect(commandLineSettingsErr).ToNot(HaveOccurred()) 937 Expect(settings.Buildpacks).To(ConsistOf("some-buildpack")) 938 Expect(settings.Command).To(Equal(types.FilteredString{IsSet: true, Value: "echo foo bar baz"})) 939 Expect(settings.DiskQuota).To(Equal(uint64(1024))) 940 Expect(settings.HealthCheckTimeout).To(BeEquivalentTo(14)) 941 Expect(settings.HealthCheckType).To(Equal("http")) 942 Expect(settings.Instances).To(Equal(types.NullInt{Value: 12, IsSet: true})) 943 Expect(settings.Memory).To(Equal(uint64(100))) 944 Expect(settings.StackName).To(Equal("some-stack")) 945 }) 946 }) 947 948 Context("route related flags", func() { 949 When("given customed route settings", func() { 950 BeforeEach(func() { 951 cmd.Domain = "some-domain" 952 }) 953 954 It("sets NoHostname on the command line settings", func() { 955 Expect(settings.DefaultRouteDomain).To(Equal("some-domain")) 956 }) 957 }) 958 959 When("--hostname is given", func() { 960 BeforeEach(func() { 961 cmd.Hostname = "some-hostname" 962 }) 963 964 It("sets DefaultRouteHostname on the command line settings", func() { 965 Expect(settings.DefaultRouteHostname).To(Equal("some-hostname")) 966 }) 967 }) 968 969 When("--no-hostname is given", func() { 970 BeforeEach(func() { 971 cmd.NoHostname = true 972 }) 973 974 It("sets NoHostname on the command line settings", func() { 975 Expect(settings.NoHostname).To(BeTrue()) 976 }) 977 }) 978 979 When("--random-route is given", func() { 980 BeforeEach(func() { 981 cmd.RandomRoute = true 982 }) 983 984 It("sets --random-route on the command line settings", func() { 985 Expect(commandLineSettingsErr).ToNot(HaveOccurred()) 986 Expect(settings.RandomRoute).To(BeTrue()) 987 }) 988 }) 989 990 When("--route-path is given", func() { 991 BeforeEach(func() { 992 cmd.RoutePath = flag.RoutePath{Path: "/some-path"} 993 }) 994 995 It("sets --route-path on the command line settings", func() { 996 Expect(commandLineSettingsErr).ToNot(HaveOccurred()) 997 Expect(settings.RoutePath).To(Equal("/some-path")) 998 }) 999 }) 1000 1001 When("--no-route is given", func() { 1002 BeforeEach(func() { 1003 cmd.NoRoute = true 1004 }) 1005 1006 It("sets NoRoute on the command line settings", func() { 1007 Expect(settings.NoRoute).To(BeTrue()) 1008 }) 1009 }) 1010 }) 1011 1012 Context("app bits", func() { 1013 When("-p flag is given", func() { 1014 BeforeEach(func() { 1015 cmd.AppPath = "some-directory-path" 1016 }) 1017 1018 It("sets ProvidedAppPath", func() { 1019 Expect(settings.ProvidedAppPath).To(Equal("some-directory-path")) 1020 }) 1021 }) 1022 1023 When("the -o flag is given", func() { 1024 BeforeEach(func() { 1025 cmd.DockerImage.Path = "some-docker-image-path" 1026 }) 1027 1028 It("creates command line setting from command line arguments", func() { 1029 Expect(settings.DockerImage).To(Equal("some-docker-image-path")) 1030 }) 1031 1032 Context("--docker-username flags is given", func() { 1033 BeforeEach(func() { 1034 cmd.DockerUsername = "some-docker-username" 1035 }) 1036 1037 Context("the docker password environment variable is set", func() { 1038 BeforeEach(func() { 1039 fakeConfig.DockerPasswordReturns("some-docker-password") 1040 }) 1041 1042 It("creates command line setting from command line arguments and config", func() { 1043 Expect(testUI.Out).To(Say("Using docker repository password from environment variable CF_DOCKER_PASSWORD.")) 1044 1045 Expect(settings.Name).To(Equal(appName)) 1046 Expect(settings.DockerImage).To(Equal("some-docker-image-path")) 1047 Expect(settings.DockerUsername).To(Equal("some-docker-username")) 1048 Expect(settings.DockerPassword).To(Equal("some-docker-password")) 1049 }) 1050 }) 1051 1052 Context("the docker password environment variable is *not* set", func() { 1053 BeforeEach(func() { 1054 input.Write([]byte("some-docker-password\n")) 1055 }) 1056 1057 It("prompts the user for a password", func() { 1058 Expect(testUI.Out).To(Say("Environment variable CF_DOCKER_PASSWORD not set.")) 1059 Expect(testUI.Out).To(Say("Docker password")) 1060 1061 Expect(settings.Name).To(Equal(appName)) 1062 Expect(settings.DockerImage).To(Equal("some-docker-image-path")) 1063 Expect(settings.DockerUsername).To(Equal("some-docker-username")) 1064 Expect(settings.DockerPassword).To(Equal("some-docker-password")) 1065 }) 1066 }) 1067 }) 1068 }) 1069 }) 1070 }) 1071 1072 DescribeTable("validation errors when flags are passed", 1073 func(setup func(), expectedErr error) { 1074 setup() 1075 _, commandLineSettingsErr := cmd.GetCommandLineSettings() 1076 Expect(commandLineSettingsErr).To(MatchError(expectedErr)) 1077 }, 1078 1079 Entry("--droplet and --docker-username", 1080 func() { 1081 cmd.DropletPath = "some-droplet-path" 1082 cmd.DockerUsername = "some-docker-username" 1083 }, 1084 translatableerror.ArgumentCombinationError{Args: []string{"--droplet", "--docker-username", "-p"}}), 1085 1086 Entry("--droplet and --docker-image", 1087 func() { 1088 cmd.DropletPath = "some-droplet-path" 1089 cmd.DockerImage.Path = "some-docker-image" 1090 }, 1091 translatableerror.ArgumentCombinationError{Args: []string{"--droplet", "--docker-image", "-o"}}), 1092 1093 Entry("--droplet and -p", 1094 func() { 1095 cmd.DropletPath = "some-droplet-path" 1096 cmd.AppPath = "some-directory-path" 1097 }, 1098 translatableerror.ArgumentCombinationError{Args: []string{"--droplet", "-p"}}), 1099 1100 Entry("-o and -p", 1101 func() { 1102 cmd.DockerImage.Path = "some-docker-image" 1103 cmd.AppPath = "some-directory-path" 1104 }, 1105 translatableerror.ArgumentCombinationError{Args: []string{"--docker-image, -o", "-p"}}), 1106 1107 Entry("-b and --docker-image", 1108 func() { 1109 cmd.DockerImage.Path = "some-docker-image" 1110 cmd.Buildpacks = []string{"some-buildpack"} 1111 }, 1112 translatableerror.ArgumentCombinationError{Args: []string{"-b", "--docker-image, -o"}}), 1113 1114 Entry("--docker-username (without DOCKER_PASSWORD env set)", 1115 func() { 1116 cmd.DockerUsername = "some-docker-username" 1117 }, 1118 translatableerror.RequiredFlagsError{Arg1: "--docker-image, -o", Arg2: "--docker-username"}), 1119 1120 Entry("-d and --no-route", 1121 func() { 1122 cmd.Domain = "some-domain" 1123 cmd.NoRoute = true 1124 }, 1125 translatableerror.ArgumentCombinationError{Args: []string{"-d", "--no-route"}}), 1126 1127 Entry("--hostname and --no-hostname", 1128 func() { 1129 cmd.Hostname = "po-tate-toe" 1130 cmd.NoHostname = true 1131 }, 1132 translatableerror.ArgumentCombinationError{Args: []string{"--hostname", "-n", "--no-hostname"}}), 1133 1134 Entry("--hostname and --no-route", 1135 func() { 1136 cmd.Hostname = "po-tate-toe" 1137 cmd.NoRoute = true 1138 }, 1139 translatableerror.ArgumentCombinationError{Args: []string{"--hostname", "-n", "--no-route"}}), 1140 1141 Entry("--no-hostname and --no-route", 1142 func() { 1143 cmd.NoHostname = true 1144 cmd.NoRoute = true 1145 }, 1146 translatableerror.ArgumentCombinationError{Args: []string{"--no-hostname", "--no-route"}}), 1147 1148 Entry("-f and --no-manifest", 1149 func() { 1150 cmd.PathToManifest = "/some/path.yml" 1151 cmd.NoManifest = true 1152 }, 1153 translatableerror.ArgumentCombinationError{Args: []string{"-f", "--no-manifest"}}), 1154 1155 Entry("--random-route and --hostname", 1156 func() { 1157 cmd.Hostname = "po-tate-toe" 1158 cmd.RandomRoute = true 1159 }, 1160 translatableerror.ArgumentCombinationError{Args: []string{"--hostname", "-n", "--random-route"}}), 1161 1162 Entry("--random-route and --no-hostname", 1163 func() { 1164 cmd.RandomRoute = true 1165 cmd.NoHostname = true 1166 }, 1167 translatableerror.ArgumentCombinationError{Args: []string{"--no-hostname", "--random-route"}}), 1168 1169 Entry("--random-route and --no-route", 1170 func() { 1171 cmd.RandomRoute = true 1172 cmd.NoRoute = true 1173 }, 1174 translatableerror.ArgumentCombinationError{Args: []string{"--no-route", "--random-route"}}), 1175 1176 Entry("--random-route and --route-path", 1177 func() { 1178 cmd.RoutePath = flag.RoutePath{Path: "/bananas"} 1179 cmd.RandomRoute = true 1180 }, 1181 translatableerror.ArgumentCombinationError{Args: []string{"--random-route", "--route-path"}}), 1182 1183 Entry("--route-path and --no-route", 1184 func() { 1185 cmd.RoutePath = flag.RoutePath{Path: "/bananas"} 1186 cmd.NoRoute = true 1187 }, 1188 translatableerror.ArgumentCombinationError{Args: []string{"--route-path", "--no-route"}}), 1189 ) 1190 }) 1191 })