github.com/franc20/ayesa_sap@v7.0.0-beta.28.0.20200124003224-302d4d52fa6c+incompatible/command/v6/start_command_test.go (about) 1 package v6_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/v2action" 11 "code.cloudfoundry.org/cli/actor/v2v3action" 12 "code.cloudfoundry.org/cli/actor/v3action" 13 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv2/constant" 14 "code.cloudfoundry.org/cli/command/commandfakes" 15 "code.cloudfoundry.org/cli/command/translatableerror" 16 . "code.cloudfoundry.org/cli/command/v6" 17 "code.cloudfoundry.org/cli/command/v6/shared/sharedfakes" 18 "code.cloudfoundry.org/cli/command/v6/v6fakes" 19 "code.cloudfoundry.org/cli/types" 20 "code.cloudfoundry.org/cli/util/configv3" 21 "code.cloudfoundry.org/cli/util/ui" 22 . "github.com/onsi/ginkgo" 23 . "github.com/onsi/gomega" 24 . "github.com/onsi/gomega/gbytes" 25 ) 26 27 // Used for command/v6 tests that need a `GetStreamingLogs' stub 28 func GetStreamingLogsStub(logMessages []string, errorStrings []string) (chan bool, func(appGUID string, client sharedaction.LogCacheClient) (<-chan sharedaction.LogMessage, <-chan error, context.CancelFunc)) { 29 var closedTheStreams bool 30 allLogsWritten := make(chan bool) 31 return allLogsWritten, func(appGUID string, client sharedaction.LogCacheClient) (<-chan sharedaction.LogMessage, <-chan error, context.CancelFunc) { 32 33 outgoingLogStream := make(chan sharedaction.LogMessage, 1) 34 outgoingErrStream := make(chan error, 1) 35 cancelFunc := func() { 36 if closedTheStreams { 37 return 38 } 39 closedTheStreams = true 40 close(outgoingLogStream) 41 close(outgoingErrStream) 42 } 43 44 closedTheStreams = false 45 go func() { 46 for _, s := range logMessages { 47 outgoingLogStream <- *sharedaction.NewLogMessage(s, "OUT", time.Now(), sharedaction.StagingLog, "source-instance") 48 } 49 for _, s := range errorStrings { 50 outgoingErrStream <- errors.New(s) 51 } 52 allLogsWritten <- true 53 }() 54 return outgoingLogStream, outgoingErrStream, cancelFunc 55 } 56 } 57 58 var _ = Describe("Start Command", func() { 59 var ( 60 cmd StartCommand 61 testUI *ui.UI 62 fakeConfig *commandfakes.FakeConfig 63 fakeSharedActor *commandfakes.FakeSharedActor 64 fakeActor *v6fakes.FakeStartActor 65 fakeApplicationSummaryActor *sharedfakes.FakeApplicationSummaryActor 66 binaryName string 67 appName string 68 executeErr error 69 allLogsWritten chan bool 70 ) 71 72 BeforeEach(func() { 73 testUI = ui.NewTestUI(nil, NewBuffer(), NewBuffer()) 74 fakeConfig = new(commandfakes.FakeConfig) 75 fakeSharedActor = new(commandfakes.FakeSharedActor) 76 fakeActor = new(v6fakes.FakeStartActor) 77 fakeApplicationSummaryActor = new(sharedfakes.FakeApplicationSummaryActor) 78 79 cmd = StartCommand{ 80 UI: testUI, 81 Config: fakeConfig, 82 SharedActor: fakeSharedActor, 83 Actor: fakeActor, 84 ApplicationSummaryActor: fakeApplicationSummaryActor, 85 } 86 87 appName = "some-app" 88 cmd.RequiredArgs.AppName = appName 89 90 binaryName = "faceman" 91 fakeConfig.BinaryNameReturns(binaryName) 92 93 var err error 94 testUI.TimezoneLocation, err = time.LoadLocation("America/Los_Angeles") 95 Expect(err).NotTo(HaveOccurred()) 96 97 allLogsWritten, fakeActor.GetStreamingLogsStub = GetStreamingLogsStub([]string{}, []string{}) 98 fakeActor.StartApplicationStub = func(app v2action.Application) (<-chan v2action.ApplicationStateChange, <-chan string, <-chan error) { 99 appState := make(chan v2action.ApplicationStateChange) 100 warnings := make(chan string) 101 errs := make(chan error) 102 103 go func() { 104 <-allLogsWritten 105 close(appState) 106 close(warnings) 107 close(errs) 108 }() 109 110 return appState, warnings, errs 111 } 112 }) 113 114 JustBeforeEach(func() { 115 executeErr = cmd.Execute(nil) 116 }) 117 118 When("checking target fails", func() { 119 BeforeEach(func() { 120 fakeSharedActor.CheckTargetReturns(actionerror.NotLoggedInError{BinaryName: binaryName}) 121 }) 122 123 It("returns an error if the check fails", func() { 124 Expect(executeErr).To(MatchError(actionerror.NotLoggedInError{BinaryName: "faceman"})) 125 126 Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1)) 127 checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0) 128 Expect(checkTargetedOrg).To(BeTrue()) 129 Expect(checkTargetedSpace).To(BeTrue()) 130 }) 131 }) 132 133 When("the user is logged in, and org and space are targeted", func() { 134 BeforeEach(func() { 135 fakeConfig.HasTargetedOrganizationReturns(true) 136 fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: "some-org"}) 137 fakeConfig.HasTargetedSpaceReturns(true) 138 fakeConfig.TargetedSpaceReturns(configv3.Space{ 139 GUID: "some-space-guid", 140 Name: "some-space"}) 141 fakeConfig.CurrentUserReturns( 142 configv3.User{Name: "some-user"}, 143 nil) 144 }) 145 146 When("getting the current user returns an error", func() { 147 var expectedErr error 148 149 BeforeEach(func() { 150 expectedErr = errors.New("getting current user error") 151 fakeConfig.CurrentUserReturns( 152 configv3.User{}, 153 expectedErr) 154 }) 155 156 It("returns the error", func() { 157 Expect(executeErr).To(MatchError(expectedErr)) 158 }) 159 }) 160 161 It("displays flavor text", func() { 162 Expect(testUI.Out).To(Say("Starting app %s in org some-org / space some-space as some-user...", appName)) 163 }) 164 165 When("the app exists", func() { 166 When("the app is already started", func() { 167 BeforeEach(func() { 168 fakeActor.GetApplicationByNameAndSpaceReturns( 169 v2action.Application{State: constant.ApplicationStarted}, 170 v2action.Warnings{"warning-1", "warning-2"}, 171 nil, 172 ) 173 }) 174 175 It("short circuits and displays message", func() { 176 Expect(executeErr).ToNot(HaveOccurred()) 177 178 Expect(testUI.Out).To(Say("App %s is already started", appName)) 179 180 Expect(testUI.Err).To(Say("warning-1")) 181 Expect(testUI.Err).To(Say("warning-2")) 182 183 Expect(fakeActor.StartApplicationCallCount()).To(Equal(0)) 184 }) 185 }) 186 187 When("the app is not already started", func() { 188 BeforeEach(func() { 189 fakeActor.GetApplicationByNameAndSpaceReturns( 190 v2action.Application{GUID: "app-guid", State: constant.ApplicationStopped}, 191 v2action.Warnings{"warning-1", "warning-2"}, 192 nil, 193 ) 194 }) 195 196 It("starts the app", func() { 197 Expect(executeErr).ToNot(HaveOccurred()) 198 199 Expect(testUI.Err).To(Say("warning-1")) 200 Expect(testUI.Err).To(Say("warning-2")) 201 202 Expect(fakeActor.StartApplicationCallCount()).To(Equal(1)) 203 app := fakeActor.StartApplicationArgsForCall(0) 204 Expect(app.GUID).To(Equal("app-guid")) 205 }) 206 207 When("passed an ApplicationStateStarting message", func() { 208 BeforeEach(func() { 209 fakeActor.StartApplicationStub = func(app v2action.Application) (<-chan v2action.ApplicationStateChange, <-chan string, <-chan error) { 210 appState := make(chan v2action.ApplicationStateChange) 211 warnings := make(chan string) 212 errs := make(chan error) 213 214 go func() { 215 <-allLogsWritten 216 appState <- v2action.ApplicationStateStarting 217 close(appState) 218 close(warnings) 219 close(errs) 220 }() 221 222 return appState, warnings, errs 223 } 224 }) 225 226 It("displays the log", func() { 227 Expect(executeErr).ToNot(HaveOccurred()) 228 Expect(testUI.Out).To(Say("Waiting for app to start...")) 229 }) 230 231 When("passed both an ApplicationStateStarting message and a log message", func() { 232 BeforeEach(func() { 233 allLogsWritten, fakeActor.GetStreamingLogsStub = GetStreamingLogsStub([]string{"log message 1", "log message 2"}, []string{}) 234 }) 235 It("displays the log messages first", func() { 236 Expect(executeErr).ToNot(HaveOccurred()) 237 Expect(testUI.Out).To(Say("log message 1")) 238 Expect(testUI.Out).To(Say("log message 2")) 239 Expect(testUI.Out).To(Say("Waiting for app to start...")) 240 241 }) 242 }) 243 }) 244 245 When("passed a log message", func() { 246 BeforeEach(func() { 247 allLogsWritten, fakeActor.GetStreamingLogsStub = GetStreamingLogsStub([]string{"log message 1", "log message 2"}, []string{}) 248 fakeActor.StartApplicationStub = func(app v2action.Application) (<-chan v2action.ApplicationStateChange, <-chan string, <-chan error) { 249 appState := make(chan v2action.ApplicationStateChange) 250 warnings := make(chan string) 251 errs := make(chan error) 252 253 go func() { 254 <-allLogsWritten 255 close(appState) 256 close(warnings) 257 close(errs) 258 }() 259 260 return appState, warnings, errs 261 } 262 }) 263 264 It("displays the log", func() { 265 Expect(executeErr).ToNot(HaveOccurred()) 266 Expect(testUI.Out).To(Say("log message 1")) 267 Expect(testUI.Out).To(Say("log message 2")) 268 Expect(testUI.Out).ToNot(Say("log message 3")) 269 }) 270 }) 271 272 When("passed an log err", func() { 273 Context("NOAA connection times out/closes", func() { 274 BeforeEach(func() { 275 allLogsWritten, fakeActor.GetStreamingLogsStub = GetStreamingLogsStub([]string{"message 1", "message 2", "message 3"}, 276 []string{"timeout connecting to log server, no log will be shown"}, 277 ) 278 fakeActor.StartApplicationStub = func(app v2action.Application) (<-chan v2action.ApplicationStateChange, <-chan string, <-chan error) { 279 appState := make(chan v2action.ApplicationStateChange) 280 warnings := make(chan string) 281 errs := make(chan error) 282 283 go func() { 284 <-allLogsWritten 285 close(appState) 286 close(warnings) 287 close(errs) 288 }() 289 290 return appState, warnings, errs 291 } 292 v3ApplicationSummary := v3action.ApplicationSummary{ 293 Application: v3action.Application{ 294 Name: appName, 295 }, 296 ProcessSummaries: v3action.ProcessSummaries{ 297 { 298 Process: v3action.Process{ 299 Type: "aba", 300 Command: *types.NewFilteredString("some-command-1"), 301 MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, 302 DiskInMB: types.NullUint64{Value: 1024, IsSet: true}, 303 }, 304 }, 305 { 306 Process: v3action.Process{ 307 Type: "console", 308 Command: *types.NewFilteredString("some-command-2"), 309 MemoryInMB: types.NullUint64{Value: 16, IsSet: true}, 310 DiskInMB: types.NullUint64{Value: 512, IsSet: true}, 311 }, 312 }, 313 }, 314 } 315 316 applicationSummary := v2v3action.ApplicationSummary{ 317 ApplicationSummary: v3ApplicationSummary, 318 } 319 320 warnings := []string{"app-summary-warning"} 321 322 fakeApplicationSummaryActor.GetApplicationSummaryByNameAndSpaceReturns(applicationSummary, warnings, nil) 323 }) 324 325 It("displays a warning and continues until app has started", func() { 326 Expect(executeErr).To(BeNil()) 327 Expect(testUI.Out).To(Say("message 1")) 328 Expect(testUI.Out).To(Say("message 2")) 329 Expect(testUI.Out).To(Say("message 3")) 330 Expect(testUI.Err).To(Say("timeout connecting to log server, no log will be shown")) 331 Expect(testUI.Out).To(Say(`name:\s+%s`, appName)) 332 }) 333 }) 334 335 Context("an unexpected error occurs", func() { 336 var expectedErr error 337 338 BeforeEach(func() { 339 expectedErr = errors.New("err log message") 340 allLogsWritten, fakeActor.GetStreamingLogsStub = GetStreamingLogsStub([]string{}, []string{expectedErr.Error()}) 341 342 fakeActor.StartApplicationStub = func(app v2action.Application) (<-chan v2action.ApplicationStateChange, <-chan string, <-chan error) { 343 appState := make(chan v2action.ApplicationStateChange) 344 warnings := make(chan string) 345 errs := make(chan error) 346 347 go func() { 348 <-allLogsWritten 349 close(appState) 350 close(warnings) 351 close(errs) 352 }() 353 354 return appState, warnings, errs 355 } 356 }) 357 358 It("displays the error and continues to poll", func() { 359 Expect(executeErr).NotTo(HaveOccurred()) 360 Expect(testUI.Err).To(Say(expectedErr.Error())) 361 }) 362 }) 363 }) 364 365 When("passed a warning", func() { 366 Context("while NOAA is still logging", func() { 367 BeforeEach(func() { 368 fakeActor.StartApplicationStub = func(app v2action.Application) (<-chan v2action.ApplicationStateChange, <-chan string, <-chan error) { 369 appState := make(chan v2action.ApplicationStateChange) 370 warnings := make(chan string) 371 errs := make(chan error) 372 373 go func() { 374 <-allLogsWritten 375 warnings <- "warning 1" 376 warnings <- "warning 2" 377 close(appState) 378 close(warnings) 379 close(errs) 380 }() 381 382 return appState, warnings, errs 383 } 384 }) 385 386 It("displays the warnings to STDERR", func() { 387 Expect(executeErr).ToNot(HaveOccurred()) 388 Expect(testUI.Err).To(Say("warning 1")) 389 Expect(testUI.Err).To(Say("warning 2")) 390 }) 391 }) 392 393 Context("while NOAA is no longer logging", func() { 394 BeforeEach(func() { 395 fakeActor.StartApplicationStub = func(app v2action.Application) (<-chan v2action.ApplicationStateChange, <-chan string, <-chan error) { 396 appState := make(chan v2action.ApplicationStateChange) 397 warnings := make(chan string) 398 errs := make(chan error) 399 400 go func() { 401 <-allLogsWritten 402 warnings <- "warning 1" 403 warnings <- "warning 2" 404 warnings <- "warning 3" 405 warnings <- "warning 4" 406 close(appState) 407 close(warnings) 408 close(errs) 409 }() 410 411 return appState, warnings, errs 412 } 413 }) 414 415 It("displays the warnings to STDERR", func() { 416 Expect(executeErr).ToNot(HaveOccurred()) 417 Expect(testUI.Err).To(Say("warning 1")) 418 Expect(testUI.Err).To(Say("warning 2")) 419 Expect(testUI.Err).To(Say("warning 3")) 420 Expect(testUI.Err).To(Say("warning 4")) 421 }) 422 }) 423 }) 424 425 When("passed an API err", func() { 426 var apiErr error 427 428 BeforeEach(func() { 429 fakeActor.StartApplicationStub = func(app v2action.Application) (<-chan v2action.ApplicationStateChange, <-chan string, <-chan error) { 430 appState := make(chan v2action.ApplicationStateChange) 431 warnings := make(chan string) 432 errs := make(chan error) 433 434 go func() { 435 <-allLogsWritten 436 errs <- apiErr 437 close(appState) 438 close(warnings) 439 close(errs) 440 }() 441 442 return appState, warnings, errs 443 } 444 }) 445 446 Context("an unexpected error", func() { 447 BeforeEach(func() { 448 apiErr = errors.New("err log message") 449 }) 450 451 It("stops logging and returns the error", func() { 452 Expect(executeErr).To(MatchError(apiErr)) 453 }) 454 }) 455 456 Context("staging failed", func() { 457 BeforeEach(func() { 458 apiErr = actionerror.StagingFailedError{Reason: "Something, but not nothing"} 459 }) 460 461 It("stops logging and returns StagingFailedError", func() { 462 Expect(executeErr).To(MatchError(translatableerror.StagingFailedError{Message: "Something, but not nothing"})) 463 }) 464 }) 465 466 Context("staging timed out", func() { 467 BeforeEach(func() { 468 apiErr = actionerror.StagingTimeoutError{AppName: appName, Timeout: time.Nanosecond} 469 }) 470 471 It("stops logging and returns StagingTimeoutError", func() { 472 Expect(executeErr).To(MatchError(translatableerror.StagingTimeoutError{AppName: appName, Timeout: time.Nanosecond})) 473 }) 474 }) 475 476 When("the app instance crashes", func() { 477 BeforeEach(func() { 478 apiErr = actionerror.ApplicationInstanceCrashedError{Name: appName} 479 }) 480 481 It("stops logging and returns ApplicationUnableToStartError", func() { 482 Expect(executeErr).To(MatchError(translatableerror.ApplicationUnableToStartError{AppName: appName, BinaryName: "faceman"})) 483 }) 484 }) 485 486 When("the app instance flaps", func() { 487 BeforeEach(func() { 488 apiErr = actionerror.ApplicationInstanceFlappingError{Name: appName} 489 }) 490 491 It("stops logging and returns ApplicationUnableToStartError", func() { 492 Expect(executeErr).To(MatchError(translatableerror.ApplicationUnableToStartError{AppName: appName, BinaryName: "faceman"})) 493 }) 494 }) 495 496 Context("starting timeout", func() { 497 BeforeEach(func() { 498 apiErr = actionerror.StartupTimeoutError{Name: appName} 499 }) 500 501 It("stops logging and returns StartupTimeoutError", func() { 502 Expect(executeErr).To(MatchError(translatableerror.StartupTimeoutError{AppName: appName, BinaryName: "faceman"})) 503 }) 504 }) 505 }) 506 507 When("the app finishes starting", func() { 508 Describe("version-dependent display", func() { 509 When("CC API >= 3.27.0", func() { 510 var ( 511 applicationSummary v2v3action.ApplicationSummary 512 ) 513 514 BeforeEach(func() { 515 fakeApplicationSummaryActor.CloudControllerV3APIVersionReturns("3.50.0") 516 v3ApplicationSummary := v3action.ApplicationSummary{ 517 Application: v3action.Application{ 518 Name: appName, 519 }, 520 ProcessSummaries: v3action.ProcessSummaries{ 521 { 522 Process: v3action.Process{ 523 Type: "aba", 524 Command: *types.NewFilteredString("some-command-1"), 525 MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, 526 DiskInMB: types.NullUint64{Value: 1024, IsSet: true}, 527 }, 528 }, 529 { 530 Process: v3action.Process{ 531 Type: "console", 532 Command: *types.NewFilteredString("some-command-2"), 533 MemoryInMB: types.NullUint64{Value: 16, IsSet: true}, 534 DiskInMB: types.NullUint64{Value: 512, IsSet: true}, 535 }, 536 }, 537 }, 538 } 539 applicationSummary = v2v3action.ApplicationSummary{ 540 ApplicationSummary: v3ApplicationSummary, 541 } 542 543 fakeApplicationSummaryActor.GetApplicationSummaryByNameAndSpaceReturns( 544 applicationSummary, 545 v2v3action.Warnings{"combo-summary-warning"}, 546 nil) 547 548 }) 549 550 It("uses the multiprocess display", func() { 551 Expect(executeErr).ToNot(HaveOccurred()) 552 553 Expect(fakeApplicationSummaryActor.GetApplicationSummaryByNameAndSpaceCallCount()).To(Equal(1)) 554 passedAppName, spaceGUID, withObfuscatedValues := fakeApplicationSummaryActor.GetApplicationSummaryByNameAndSpaceArgsForCall(0) 555 Expect(passedAppName).To(Equal(appName)) 556 Expect(spaceGUID).To(Equal("some-space-guid")) 557 Expect(withObfuscatedValues).To(BeTrue()) 558 559 Expect(testUI.Out).To(Say(`name:\s+%s`, appName)) 560 Expect(testUI.Out).To(Say(`type:\s+aba`)) 561 Expect(testUI.Out).To(Say(`instances:\s+0/0`)) 562 Expect(testUI.Out).To(Say(`memory usage:\s+32M`)) 563 Expect(testUI.Out).To(Say(`start command:\s+some-command-1`)) 564 Expect(testUI.Out).To(Say(`type:\s+console`)) 565 Expect(testUI.Out).To(Say(`instances:\s+0/0`)) 566 Expect(testUI.Out).To(Say(`memory usage:\s+16M`)) 567 Expect(testUI.Out).To(Say(`start command:\s+some-command-2`)) 568 569 Expect(testUI.Err).To(Say("combo-summary-warning")) 570 }) 571 }) 572 }) 573 }) 574 }) 575 }) 576 577 When("the app does *not* exists", func() { 578 BeforeEach(func() { 579 fakeActor.GetApplicationByNameAndSpaceReturns( 580 v2action.Application{}, 581 v2action.Warnings{"warning-1", "warning-2"}, 582 actionerror.ApplicationNotFoundError{Name: appName}, 583 ) 584 }) 585 586 It("returns back an error", func() { 587 Expect(executeErr).To(MatchError(actionerror.ApplicationNotFoundError{Name: "some-app"})) 588 589 Expect(testUI.Err).To(Say("warning-1")) 590 Expect(testUI.Err).To(Say("warning-2")) 591 }) 592 }) 593 }) 594 })