github.com/nimakaviani/cli@v6.37.1-0.20180619223813-e734901a73fa+incompatible/command/v3/v3_app_command_test.go (about) 1 package v3_test 2 3 import ( 4 "errors" 5 "time" 6 7 "code.cloudfoundry.org/cli/actor/actionerror" 8 "code.cloudfoundry.org/cli/actor/v2action" 9 "code.cloudfoundry.org/cli/actor/v3action" 10 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 11 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" 12 "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" 13 "code.cloudfoundry.org/cli/command/commandfakes" 14 "code.cloudfoundry.org/cli/command/flag" 15 "code.cloudfoundry.org/cli/command/translatableerror" 16 "code.cloudfoundry.org/cli/command/v3" 17 "code.cloudfoundry.org/cli/command/v3/shared" 18 "code.cloudfoundry.org/cli/command/v3/shared/sharedfakes" 19 "code.cloudfoundry.org/cli/command/v3/v3fakes" 20 "code.cloudfoundry.org/cli/types" 21 "code.cloudfoundry.org/cli/util/configv3" 22 "code.cloudfoundry.org/cli/util/ui" 23 . "github.com/onsi/ginkgo" 24 . "github.com/onsi/gomega" 25 . "github.com/onsi/gomega/gbytes" 26 ) 27 28 var _ = Describe("v3-app Command", func() { 29 var ( 30 cmd v3.V3AppCommand 31 testUI *ui.UI 32 fakeConfig *commandfakes.FakeConfig 33 fakeSharedActor *commandfakes.FakeSharedActor 34 fakeActor *v3fakes.FakeV3AppActor 35 fakeV2Actor *sharedfakes.FakeV2AppRouteActor 36 binaryName string 37 executeErr error 38 app string 39 ) 40 41 BeforeEach(func() { 42 testUI = ui.NewTestUI(nil, NewBuffer(), NewBuffer()) 43 fakeConfig = new(commandfakes.FakeConfig) 44 fakeSharedActor = new(commandfakes.FakeSharedActor) 45 fakeActor = new(v3fakes.FakeV3AppActor) 46 fakeV2Actor = new(sharedfakes.FakeV2AppRouteActor) 47 48 binaryName = "faceman" 49 fakeConfig.BinaryNameReturns(binaryName) 50 app = "some-app" 51 52 appSummaryDisplayer := shared.AppSummaryDisplayer{ 53 UI: testUI, 54 Config: fakeConfig, 55 Actor: fakeActor, 56 V2AppRouteActor: fakeV2Actor, 57 AppName: app, 58 } 59 60 cmd = v3.V3AppCommand{ 61 RequiredArgs: flag.AppName{AppName: app}, 62 63 UI: testUI, 64 Config: fakeConfig, 65 SharedActor: fakeSharedActor, 66 Actor: fakeActor, 67 AppSummaryDisplayer: appSummaryDisplayer, 68 } 69 70 fakeConfig.TargetedOrganizationReturns(configv3.Organization{ 71 Name: "some-org", 72 GUID: "some-org-guid", 73 }) 74 fakeConfig.TargetedSpaceReturns(configv3.Space{ 75 Name: "some-space", 76 GUID: "some-space-guid", 77 }) 78 79 fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) 80 fakeActor.CloudControllerAPIVersionReturns(ccversion.MinVersionV3) 81 }) 82 83 JustBeforeEach(func() { 84 executeErr = cmd.Execute(nil) 85 }) 86 87 Context("when the API version is below the minimum", func() { 88 BeforeEach(func() { 89 fakeActor.CloudControllerAPIVersionReturns("0.0.0") 90 }) 91 92 It("returns a MinimumAPIVersionNotMetError", func() { 93 Expect(executeErr).To(MatchError(translatableerror.MinimumAPIVersionNotMetError{ 94 CurrentVersion: "0.0.0", 95 MinimumVersion: ccversion.MinVersionV3, 96 })) 97 }) 98 99 It("displays the experimental warning", func() { 100 Expect(testUI.Err).To(Say("This command is in EXPERIMENTAL stage and may change without notice")) 101 }) 102 }) 103 104 Context("when checking target fails", func() { 105 BeforeEach(func() { 106 fakeSharedActor.CheckTargetReturns(actionerror.NoOrganizationTargetedError{BinaryName: binaryName}) 107 }) 108 109 It("returns an error", func() { 110 Expect(executeErr).To(MatchError(actionerror.NoOrganizationTargetedError{BinaryName: binaryName})) 111 112 Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1)) 113 checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0) 114 Expect(checkTargetedOrg).To(BeTrue()) 115 Expect(checkTargetedSpace).To(BeTrue()) 116 }) 117 }) 118 119 Context("when the user is not logged in", func() { 120 var expectedErr error 121 122 BeforeEach(func() { 123 expectedErr = errors.New("some current user error") 124 fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) 125 }) 126 127 It("return an error", func() { 128 Expect(executeErr).To(Equal(expectedErr)) 129 }) 130 }) 131 132 Context("when getting the application summary returns an error", func() { 133 var expectedErr error 134 135 BeforeEach(func() { 136 expectedErr = actionerror.ApplicationNotFoundError{Name: app} 137 fakeActor.GetApplicationSummaryByNameAndSpaceReturns(v3action.ApplicationSummary{}, v3action.Warnings{"warning-1", "warning-2"}, expectedErr) 138 }) 139 140 It("returns the error and prints warnings", func() { 141 Expect(executeErr).To(Equal(actionerror.ApplicationNotFoundError{Name: app})) 142 143 Expect(testUI.Out).To(Say("Showing health and status for app some-app in org some-org / space some-space as steve\\.\\.\\.")) 144 145 Expect(testUI.Err).To(Say("warning-1")) 146 Expect(testUI.Err).To(Say("warning-2")) 147 }) 148 }) 149 150 Context("when the --guid flag is provided", func() { 151 BeforeEach(func() { 152 cmd.GUID = true 153 }) 154 155 Context("when no errors occur", func() { 156 BeforeEach(func() { 157 fakeActor.GetApplicationByNameAndSpaceReturns( 158 v3action.Application{GUID: "some-guid"}, 159 v3action.Warnings{"warning-1", "warning-2"}, 160 nil) 161 }) 162 163 It("displays the application guid and all warnings", func() { 164 Expect(executeErr).ToNot(HaveOccurred()) 165 166 Expect(testUI.Out).To(Say("some-guid")) 167 Expect(testUI.Err).To(Say("warning-1")) 168 Expect(testUI.Err).To(Say("warning-2")) 169 170 Expect(fakeActor.GetApplicationByNameAndSpaceCallCount()).To(Equal(1)) 171 appName, spaceGUID := fakeActor.GetApplicationByNameAndSpaceArgsForCall(0) 172 Expect(appName).To(Equal("some-app")) 173 Expect(spaceGUID).To(Equal("some-space-guid")) 174 }) 175 }) 176 177 Context("when an error is encountered getting the app", func() { 178 Context("when the error is translatable", func() { 179 BeforeEach(func() { 180 fakeActor.GetApplicationByNameAndSpaceReturns( 181 v3action.Application{}, 182 v3action.Warnings{"warning-1", "warning-2"}, 183 actionerror.ApplicationNotFoundError{Name: "some-app"}) 184 }) 185 186 It("returns a translatable error and all warnings", func() { 187 Expect(executeErr).To(MatchError(actionerror.ApplicationNotFoundError{Name: "some-app"})) 188 189 Expect(testUI.Err).To(Say("warning-1")) 190 Expect(testUI.Err).To(Say("warning-2")) 191 }) 192 }) 193 194 Context("when the error is not translatable", func() { 195 var expectedErr error 196 197 BeforeEach(func() { 198 expectedErr = errors.New("get app summary error") 199 fakeActor.GetApplicationByNameAndSpaceReturns( 200 v3action.Application{}, 201 v3action.Warnings{"warning-1", "warning-2"}, 202 expectedErr) 203 }) 204 205 It("returns the error and all warnings", func() { 206 Expect(executeErr).To(MatchError(expectedErr)) 207 208 Expect(testUI.Err).To(Say("warning-1")) 209 Expect(testUI.Err).To(Say("warning-2")) 210 }) 211 }) 212 }) 213 214 }) 215 216 Context("when the app is a docker app", func() { 217 BeforeEach(func() { 218 fakeActor.GetApplicationSummaryByNameAndSpaceReturns( 219 v3action.ApplicationSummary{ 220 Application: v3action.Application{ 221 GUID: "some-guid", 222 Name: "some-app", 223 State: constant.ApplicationStarted, 224 LifecycleType: constant.AppLifecycleTypeDocker, 225 }, 226 CurrentDroplet: v3action.Droplet{ 227 Image: "docker/some-image", 228 }, 229 }, 230 v3action.Warnings{"warning-1", "warning-2"}, 231 nil) 232 }) 233 234 It("displays app information without routes", func() { 235 Expect(executeErr).ToNot(HaveOccurred()) 236 237 Expect(testUI.Out).To(Say("(?m)Showing health and status for app some-app in org some-org / space some-space as steve\\.\\.\\.\n\n")) 238 Expect(testUI.Out).To(Say("name:\\s+some-app")) 239 Expect(testUI.Out).To(Say("requested state:\\s+started")) 240 Expect(testUI.Out).To(Say("processes:\\s+\\n")) 241 Expect(testUI.Out).To(Say("memory usage:\\s+\\n")) 242 Expect(testUI.Out).To(Say("routes:\\s+\\n")) 243 Expect(testUI.Out).To(Say("stack:\\s+\\n")) 244 Expect(testUI.Out).To(Say("(?m)docker image:\\s+docker/some-image$\\n")) 245 246 Expect(testUI.Err).To(Say("warning-1")) 247 Expect(testUI.Err).To(Say("warning-2")) 248 249 Expect(fakeActor.GetApplicationSummaryByNameAndSpaceCallCount()).To(Equal(1)) 250 appName, spaceGUID := fakeActor.GetApplicationSummaryByNameAndSpaceArgsForCall(0) 251 Expect(appName).To(Equal("some-app")) 252 Expect(spaceGUID).To(Equal("some-space-guid")) 253 254 Expect(fakeV2Actor.GetApplicationRoutesCallCount()).To(Equal(0)) 255 }) 256 }) 257 258 Context("when app has no processes", func() { 259 BeforeEach(func() { 260 fakeActor.GetApplicationSummaryByNameAndSpaceReturns( 261 v3action.ApplicationSummary{ 262 Application: v3action.Application{ 263 GUID: "some-guid", 264 Name: "some-app", 265 State: constant.ApplicationStarted, 266 }, 267 }, 268 v3action.Warnings{"warning-1", "warning-2"}, 269 nil) 270 }) 271 272 It("displays app information without routes", func() { 273 Expect(executeErr).ToNot(HaveOccurred()) 274 275 Expect(testUI.Out).To(Say("(?m)Showing health and status for app some-app in org some-org / space some-space as steve\\.\\.\\.\n\n")) 276 Expect(testUI.Out).To(Say("name:\\s+some-app")) 277 Expect(testUI.Out).To(Say("requested state:\\s+started")) 278 Expect(testUI.Out).To(Say("processes:\\s+\\n")) 279 Expect(testUI.Out).To(Say("memory usage:\\s+\\n")) 280 Expect(testUI.Out).To(Say("routes:\\s+\\n")) 281 Expect(testUI.Out).To(Say("stack:\\s+\\n")) 282 Expect(testUI.Out).To(Say("(?m)buildpacks:\\s+$\\n")) 283 284 Expect(testUI.Err).To(Say("warning-1")) 285 Expect(testUI.Err).To(Say("warning-2")) 286 287 Expect(fakeActor.GetApplicationSummaryByNameAndSpaceCallCount()).To(Equal(1)) 288 appName, spaceGUID := fakeActor.GetApplicationSummaryByNameAndSpaceArgsForCall(0) 289 Expect(appName).To(Equal("some-app")) 290 Expect(spaceGUID).To(Equal("some-space-guid")) 291 292 Expect(fakeV2Actor.GetApplicationRoutesCallCount()).To(Equal(0)) 293 }) 294 }) 295 296 Context("when app has processes", func() { 297 Context("when getting routes returns an error", func() { 298 var expectedErr error 299 300 BeforeEach(func() { 301 expectedErr = ccerror.RequestError{} 302 summary := v3action.ApplicationSummary{ 303 Application: v3action.Application{ 304 Name: "some-app", 305 State: constant.ApplicationStarted, 306 }, 307 ProcessSummaries: []v3action.ProcessSummary{ 308 {Process: v3action.Process{Type: constant.ProcessTypeWeb}}, 309 }, 310 } 311 fakeActor.GetApplicationSummaryByNameAndSpaceReturns( 312 summary, 313 v3action.Warnings{"warning-1", "warning-2"}, 314 nil, 315 ) 316 317 fakeV2Actor.GetApplicationRoutesReturns([]v2action.Route{}, v2action.Warnings{"route-warning-1", "route-warning-2"}, expectedErr) 318 }) 319 320 It("returns the error and prints warnings", func() { 321 Expect(executeErr).To(Equal(ccerror.RequestError{})) 322 323 Expect(testUI.Out).To(Say("Showing health and status for app some-app in org some-org / space some-space as steve\\.\\.\\.")) 324 325 Expect(testUI.Err).To(Say("warning-1")) 326 Expect(testUI.Err).To(Say("warning-2")) 327 Expect(testUI.Err).To(Say("route-warning-1")) 328 Expect(testUI.Err).To(Say("route-warning-2")) 329 }) 330 }) 331 332 Context("when getting routes does not return any errors", func() { 333 BeforeEach(func() { 334 fakeV2Actor.GetApplicationRoutesReturns([]v2action.Route{ 335 {Domain: v2action.Domain{Name: "some-other-domain"}}, { 336 Domain: v2action.Domain{Name: "some-domain"}}}, 337 v2action.Warnings{"route-warning-1", "route-warning-2"}, nil) 338 }) 339 340 Context("when there are no instances of any process in the app", func() { 341 BeforeEach(func() { 342 summary := v3action.ApplicationSummary{ 343 Application: v3action.Application{ 344 Name: "some-app", 345 State: constant.ApplicationStarted, 346 }, 347 CurrentDroplet: v3action.Droplet{ 348 Stack: "cflinuxfs2", 349 Buildpacks: []v3action.Buildpack{ 350 { 351 Name: "ruby_buildpack", 352 DetectOutput: "some-detect-output", 353 }, 354 { 355 Name: "some-buildpack", 356 DetectOutput: "", 357 }, 358 }, 359 }, 360 ProcessSummaries: []v3action.ProcessSummary{ 361 { 362 Process: v3action.Process{ 363 Type: "console", 364 MemoryInMB: types.NullUint64{Value: 128, IsSet: true}, 365 }, 366 }, 367 { 368 Process: v3action.Process{ 369 Type: "worker", 370 MemoryInMB: types.NullUint64{Value: 64, IsSet: true}, 371 }, 372 }, 373 { 374 Process: v3action.Process{ 375 Type: constant.ProcessTypeWeb, 376 MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, 377 }, 378 }, 379 }, 380 } 381 fakeActor.GetApplicationSummaryByNameAndSpaceReturns(summary, nil, nil) 382 }) 383 384 It("says no instances are running", func() { 385 Expect(executeErr).ToNot(HaveOccurred()) 386 387 Expect(testUI.Out).To(Say("There are no running instances of this app.")) 388 }) 389 390 It("does not display the instance table", func() { 391 Expect(executeErr).ToNot(HaveOccurred()) 392 393 Expect(testUI.Out).NotTo(Say(`state\s+since\s+cpu\s+memory\s+disk`)) 394 }) 395 }) 396 397 Context("when all the instances in all processes are down", func() { 398 BeforeEach(func() { 399 summary := v3action.ApplicationSummary{ 400 Application: v3action.Application{ 401 Name: "some-app", 402 State: constant.ApplicationStarted, 403 }, 404 CurrentDroplet: v3action.Droplet{ 405 Stack: "cflinuxfs2", 406 Buildpacks: []v3action.Buildpack{ 407 { 408 Name: "ruby_buildpack", 409 DetectOutput: "some-detect-output", 410 }, 411 { 412 Name: "some-buildpack", 413 DetectOutput: "", 414 }, 415 }, 416 }, 417 ProcessSummaries: []v3action.ProcessSummary{ 418 { 419 Process: v3action.Process{ 420 Type: "console", 421 MemoryInMB: types.NullUint64{Value: 128, IsSet: true}, 422 }, 423 InstanceDetails: []v3action.ProcessInstance{{State: constant.ProcessInstanceDown}}, 424 }, 425 { 426 Process: v3action.Process{ 427 Type: "worker", 428 MemoryInMB: types.NullUint64{Value: 64, IsSet: true}, 429 }, 430 InstanceDetails: []v3action.ProcessInstance{{State: constant.ProcessInstanceDown}}, 431 }, 432 { 433 Process: v3action.Process{ 434 Type: constant.ProcessTypeWeb, 435 MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, 436 }, 437 InstanceDetails: []v3action.ProcessInstance{{State: constant.ProcessInstanceDown}}, 438 }, 439 }, 440 } 441 fakeActor.GetApplicationSummaryByNameAndSpaceReturns(summary, nil, nil) 442 }) 443 444 It("says no instances are running", func() { 445 Expect(executeErr).ToNot(HaveOccurred()) 446 Expect(testUI.Out).To(Say("buildpacks:")) 447 Expect(testUI.Out).To(Say("\n\n")) 448 449 Expect(testUI.Out).To(Say("There are no running instances of this app.")) 450 }) 451 452 It("does not display the instance table", func() { 453 Expect(executeErr).ToNot(HaveOccurred()) 454 455 Expect(testUI.Out).NotTo(Say(`state\s+since\s+cpu\s+memory\s+disk`)) 456 }) 457 }) 458 459 Context("when there are running instances of the app", func() { 460 BeforeEach(func() { 461 summary := v3action.ApplicationSummary{ 462 Application: v3action.Application{ 463 Name: "some-app", 464 State: constant.ApplicationStarted, 465 }, 466 CurrentDroplet: v3action.Droplet{ 467 Stack: "cflinuxfs2", 468 Buildpacks: []v3action.Buildpack{ 469 { 470 Name: "ruby_buildpack", 471 DetectOutput: "some-detect-output", 472 }, 473 { 474 Name: "some-buildpack", 475 DetectOutput: "", 476 }, 477 }, 478 }, 479 ProcessSummaries: []v3action.ProcessSummary{ 480 { 481 Process: v3action.Process{ 482 Type: "console", 483 MemoryInMB: types.NullUint64{Value: 128, IsSet: true}, 484 }, 485 InstanceDetails: []v3action.ProcessInstance{}, 486 }, 487 { 488 Process: v3action.Process{ 489 Type: "worker", 490 MemoryInMB: types.NullUint64{Value: 64, IsSet: true}, 491 }, 492 InstanceDetails: []v3action.ProcessInstance{ 493 v3action.ProcessInstance{ 494 Index: 0, 495 State: constant.ProcessInstanceDown, 496 MemoryUsage: 4000000, 497 DiskUsage: 4000000, 498 MemoryQuota: 67108864, 499 DiskQuota: 8000000, 500 Uptime: int(time.Now().Sub(time.Unix(1371859200, 0)).Seconds()), 501 }, 502 }, 503 }, 504 { 505 Process: v3action.Process{ 506 Type: constant.ProcessTypeWeb, 507 MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, 508 }, 509 InstanceDetails: []v3action.ProcessInstance{ 510 v3action.ProcessInstance{ 511 Index: 0, 512 State: constant.ProcessInstanceRunning, 513 MemoryUsage: 1000000, 514 DiskUsage: 1000000, 515 MemoryQuota: 33554432, 516 DiskQuota: 2000000, 517 Uptime: int(time.Now().Sub(time.Unix(267321600, 0)).Seconds()), 518 }, 519 v3action.ProcessInstance{ 520 Index: 1, 521 State: constant.ProcessInstanceRunning, 522 MemoryUsage: 2000000, 523 DiskUsage: 2000000, 524 MemoryQuota: 33554432, 525 DiskQuota: 4000000, 526 Uptime: int(time.Now().Sub(time.Unix(330480000, 0)).Seconds()), 527 }, 528 v3action.ProcessInstance{ 529 Index: 2, 530 State: constant.ProcessInstanceRunning, 531 MemoryUsage: 3000000, 532 DiskUsage: 3000000, 533 MemoryQuota: 33554432, 534 DiskQuota: 6000000, 535 Uptime: int(time.Now().Sub(time.Unix(1277164800, 0)).Seconds()), 536 }, 537 }, 538 }, 539 }, 540 } 541 fakeActor.GetApplicationSummaryByNameAndSpaceReturns(summary, v3action.Warnings{"warning-1", "warning-2"}, nil) 542 }) 543 544 It("prints the application summary and outputs warnings", func() { 545 Expect(executeErr).ToNot(HaveOccurred()) 546 547 Expect(testUI.Out).To(Say("(?m)Showing health and status for app some-app in org some-org / space some-space as steve\\.\\.\\.\n\n")) 548 Expect(testUI.Out).To(Say("name:\\s+some-app")) 549 Expect(testUI.Out).To(Say("requested state:\\s+started")) 550 Expect(testUI.Out).To(Say("processes:\\s+web:3/3, console:0/0, worker:0/1")) 551 Expect(testUI.Out).To(Say("memory usage:\\s+32M x 3, 64M x 1")) 552 Expect(testUI.Out).To(Say("routes:\\s+some-other-domain, some-domain")) 553 Expect(testUI.Out).To(Say("stack:\\s+cflinuxfs2")) 554 Expect(testUI.Out).To(Say("(?m)buildpacks:\\s+some-detect-output, some-buildpack\n\n")) 555 Expect(testUI.Out).To(Say("web:3/3")) 556 Expect(testUI.Out).To(Say("\\s+state\\s+since\\s+cpu\\s+memory\\s+disk")) 557 Expect(testUI.Out).To(Say("#0\\s+running\\s+1978-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M\\s+0.0%\\s+976.6K of 32M\\s+976.6K of 1.9M")) 558 Expect(testUI.Out).To(Say("#1\\s+running\\s+1980-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M\\s+0.0%\\s+1.9M of 32M\\s+1.9M of 3.8M")) 559 Expect(testUI.Out).To(Say("#2\\s+running\\s+2010-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M\\s+0.0%\\s+2.9M of 32M\\s+2.9M of 5.7M")) 560 561 Expect(testUI.Out).To(Say("console:0/0")) 562 563 Expect(testUI.Out).To(Say("worker:0/1")) 564 565 Expect(testUI.Err).To(Say("warning-1")) 566 Expect(testUI.Err).To(Say("warning-2")) 567 568 Expect(fakeActor.GetApplicationSummaryByNameAndSpaceCallCount()).To(Equal(1)) 569 appName, spaceGUID := fakeActor.GetApplicationSummaryByNameAndSpaceArgsForCall(0) 570 Expect(appName).To(Equal("some-app")) 571 Expect(spaceGUID).To(Equal("some-space-guid")) 572 }) 573 }) 574 }) 575 }) 576 })